-
Notifications
You must be signed in to change notification settings - Fork 0
⚙ [트러블 슈팅] Chip with TextField
이 component는 chip의 역할을 하는 component입니다. chip 내부에서 이 칩의 text가 변경이 되어야 하고, X를 눌렀을 때 이 Chip이 삭제되어야 합니다.
기존 입력이 필요하지 않았을 때는 다음과 같이 component를 구성하였습니다.
Box(
modifier = Modifier.height(32.dp),
contentAlignment = Alignment.Center
) {
InputChip(
selected = false,
onClick = onRemove,
label = {
Text(
text = item,
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
},
trailingIcon = {
Icon(
modifier = Modifier.size(18.dp),
imageVector = Icons.Outlined.Clear,
contentDescription = "trailing icon"
)
}
)
}
AddButton과 같은 크기를 유지하기 위해서 Box를 활용하였고, InputChip을 통해서 label과 trailingIcon을 설정하여 쉽게 구현하였습니다.
이 상태에서 입력이 가능하게 만들기 위해서 label 부분에 TextField
를 넣어주었습니다. 그 결과 TextField
의 Value
가 보이지 않는 버그가 발생하였습니다.
이를 정확하게 테스트 하기 위해서 Box의 height를 32.dp~56.dp까지 실험하였습니다.
이와 같은 버그가 발생하는 이유는 TextField의 내부 코드를 확인하면 BasicTextField
를 사용하여 TextField의 핵심 동작을 처리하고, TextFieldDecorationBox를 활용하여 스타일을 추가하고 있습니다. 그리고 TextField는 Material Design 가이드에 따라 defaultMinSize
로 최소 높이를 56.dp로 설정하고 있습니다.
(추가로 MinWidth는 280.dp로 설정하고 있습니다.)
또, TextField는 내부적으로 Label, Text, Placeholder, Error, Icon 등을 포함하고 있고 이 요소들을 적절하게 표시하기 위해서 일정한 공간을 확보하고 있습니다. 따라서 height를 강제로 줄이게 된다면 TextField의 content가 겹치거나 clip 될 수 있습니다.
디자인에서 height를 32.dp로 설정하기 때문에 디자인을 지키면서 component를 구현하기 위해서 BasicTextField
를 사용하였습니다.
BasicTextField
는 Jetpack Compose에서 제공하는 기본적인 텍스트 입력 필드입니다. TextField보다 더 저수준의 구현을 제공합니다. TextField와 달리 기본적인 스타일링이나 레이아웃 요소들을 제공하지 않으며, 커스터마이징에 더 유연하게 사용될 수 있습니다.
정리하면 BasicTextField
는 기본적으로 텍스트를 입력받는 기능만 제공하는 component입니다.
BasicTextField(
value = item,
onValueChange = {
if (it.length <= 10) {
onEdit(it)
}
},
textStyle = MaterialTheme.typography.labelLarge.copy(color = MaterialTheme.colorScheme.onSurfaceVariant),
modifier = Modifier.wrapContentWidth()
)
이제 위와 같이 설정하였으나 또 다른 문제가 발생하였습니다.
BasicTextField의 넓이가 글자의 길이에 맞게 설정이 되어야 하는데, 기본 넓이가 설정되어 있다는 점이었습니다.
이는 BasicTextField
내부 코드의 TextFieldTextLayoutModifier
, textFieldMinSize
에서 textStyle에 기반하여 기본 너비를 설정하고 있기 때문입니다.
정확하게는 heightInLines
에서 fontSize를 기반으로 최소 1줄 이상의 높이를 보장하고, textFieldMinSize
에서 textStyle의 fontSize
, letterSpacing
을 기반으로, 한 글자가 차지하는 기본 크기를 계산하고 최소 몇 글자가(한 줄) 담길 수 있는 너비와 높이를 강제합니다. TextFieldTextLayoutModifier
는 위와 같은 정보를 기반으로 레이아웃을 계산합니다.
IntrinsicSize
적용하여 해결하였습니다.
IntrinsicSize
는 composable의 크기를 내부 콘텐츠의 내제된 크기(Intrinsic Size)에 맞추도록 강제하는 속성입니다. 콘텐츠의 내용과 스타일에 따라 컴포저블이 얼마나 커질 수 있는지 얼마나 작아질 수 있는지 결정합니다.
IntrinsicSize.Min
을 사용하면 내부 콘텐츠의 최소 사이즈로 강제 지정합니다. 예를 들어서 32.dp
의 너비를 가진 composable과 1.dp
를 가진 composable이 자식 composable로 존재한다고 할 때, 부모 composable에 Modifier.width(IntrinsicSize.Min)
을 지정하면 부모 composable의 너비가 1.dp로 지정이 됩니다.
BasicTextField에 적용하면 텍스트의 크기가 없으면 최소 크기 요구사항이 0.dp로 처리됩니다. 따라서 레이아웃 크기를 0.dp로 설정할 수 있기 떄문에 원하는 동작을 수행하도록 구현할 수 있었습니다.
Copyright 2024. Team Kolown All Rights Reserved.
- ✅ [기술 결정] Camera
- ✅ [기술 결정] Image Load
- ✅ [기술 결정] UI Toolkit - Copmpose
- ✅ [기술 결정] 데이터 별 UID 생성
- ✅ [기술 결정] Debounce & Paging 사용해서 검색 구현
- ✅ [기술 결정] Google Login
- ✅ [기술 결정] 스켈레톤 UI
- ⚙ [기술 분석] DI
- ⚙ [기술 분석] Image Compress
- ⚙ [기술 분석] 이미지 리사이징
- ⚙ [기술 분석] CameraX API
- ⚙ [기술 분석] Firebase & 랜덤 로딩
- ⚙ [기술 분석] ViewModel 공유
- ⚙ [기술 분석] Firestore 쿼리 전략
- ⚙ [트러블 슈팅] Chip with TextField(Custom with IntrinsicSize)
- ⚙ [트러블 슈팅] WindowInset
- ⚙ [트러블 슈팅] UI 실시간 반영
- ⚙ [트러블 슈팅] IME Padding
- ⚙ [트러블 슈팅] PagingSource reset
- ⚙ [트러블 슈팅] SharedFlow - SnackBar
- ⚙ [트러블 슈팅] Camera와 Lifecycle 동기화