만들고 싶었던 것
- MaterialDesign이 적용되지 않은 `TextField`
- width가 입력되어있는 텍스트 길이 만큼 wrapCotent할 것
- Placeholder 표시
결과는 아래와 같다.
붉은 글씨 부분이 placeholder를 표시하고있는 `TextField`임
구현 과정
1. MaterialDesign이 없는 TextField
일반적인 `TextField` 컴포저블을 사용하면 MaterialDesign을 피할 수 없기 때문에,
아무 디자인도 적용되지 않은 `BasicTextField`를 사용해야 한다.
BasicTextField(
value = text,
onValueChange = { onTextChange(it) },
...
)
호출하면 기본 width를 가지는 텅빈 `TextField`가 표시된다.
(width를 표시하기 위해 회색으로 background를 칠했습니다)
2. width를 wrapContent로 만들기
`TextField`는 기본적으로 최소 width를 가지고 있는데,
이것을 제거하려면 `Modifier.width(IntrinsicSize.Min)`을 적용해야 한다.
BasicTextField(
value = text,
onValueChange = { onTextChange(it) },
modifier = Modifier.width(IntrinsicSize.Min)
)
그러면 텍스트가 없기 때문에 width가 완전히 쪼그라든다.
텍스트를 입력하면 맞춰서 길이가 늘어난다.
3. Placeholder 표시
`BasicTextField`는 placeholder를 설정하는 파라미터가 직접적으로 없다.
`TextField` 컴포저블의 구현코드를 보면 `DecorationBox`에 `placeholder`를 넘겨서 표시하고 있다.
그러면 `DecorationBox`를 사용해서 표시하면 되겠다 했는데..
`TextFieldDefaults`의 `DecorationBox`라서 그런지 저걸 사용하게 되면 MaterialDesign이 적용되어버린다.
나 뭐 어떡하라고. 커스텀 하라는거야 말라는거야
구글링 결과 그냥 때려박아버리기로 했음
Box {
var text by remember {
mutableStateOf("")
}
val hintVisible by remember {
derivedStateOf { text.isEmpty() }
}
if (hintVisible) {
// placeholder 용 Text
Text(
text = "어떤 이유"
modifier = Modifier.alpha(0.5f)
)
}
BasicTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.width(IntrinsicSize.Min)
)
}
별거 없고 그냥 입력한 텍스트가 empty면 placeholder로 사용할 `Text`를 표시하고,
텍스트가 입력되면 `Text`를 표시하지 않는다.
잘되는 것 같아 보인다.
문제
처음엔 빈칸이니까 `BasicTextField`의 width가 쪼그라든 상태라 `Box` 영역의 맨 앞부분을 터치해야만 키보드가 뜬다..
그렇다고 `BasicTextField`의 width를 `Modifier.matchParentSize`로 지정해버리면 텍스트를 입력했을 때 텍스트가 보이지 않게 된다.
`Modifier.fillMaxWidth`를 사용하면 당연히 `BasicTextField`의 width가 화면을 꽉채우게 된다.
뭐 어떡하라고.
해결
`IntrinsicSize.Min/Max`라는게 content를 그리기 위한 최소/최대의 Size를 받아와서
child를 measure 할 때 제약사항을 적용하는 것이다.
그래서 `BasicTextField`를 감싸는 상위 컴포저블인 `Box`의 width를 `IntrinsicSize.Max`로 지정하고
(-> `Box`의 width가 `BasicTextField`보다 긴 placeholder용 `Text`의 width 만큼이 됨)
`BasicTextField`의 width는 `Modifier.fillMaxWidth`로 지정해준다.
(-> `Box`의 width 제약사항 때문에 딱 `Box`의 width만큼만 fill 하게됨)
Box(
modifier = Modifier.width(IntrinsicSize.Max) // 여기
) {
var text by remember {
mutableStateOf("")
}
val hintVisible by remember {
derivedStateOf { text.isEmpty() }
}
if (hintVisible) {
// placeholder용 Text
Text(
text = "어떤 이유",
modifier = Modifier.alpha(0.5f)
)
}
BasicTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier
.fillMaxWidth() // 여기
.background(Color.LightGray.copy(alpha = 0.4f)) // width 확인용
)
}
`BasicTextField`가 빈칸인데도 placeholder의 width만큼 늘어나있는 것이 잘 보인다.
이제 어딜 눌러도 키보드가 열린다.
끝
이번 기회를 통해 `IntrinsicSize`에 대해서 정확히 알게 되었다^^
'Android' 카테고리의 다른 글
[Android] 멀티모듈에서 gradle의 BuildType 공통화 (2) | 2025.06.12 |
---|---|
[Android] java.lang.ClassCastException (0) | 2025.06.12 |
[Android] LazyColumn안에 LazyVerticalGrid 넣기(nested scroll) (0) | 2025.06.12 |
[Android] Retrofit2 Multipart사용하기 (Java) (0) | 2025.06.12 |
[Android] RecyclerView와 ListAdapter (Java) (1) | 2025.06.12 |