[Android] Compose TextField 커스텀

th.k·2024년 1월 12일
1

Android

목록 보기
7/8

만들고 싶었던 것

  • 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 컴포저블의 구현코드를 보면 DecorationBoxplaceholder를 넘겨서 표시하고 있다.

그러면 DecorationBox를 사용해서 표시하면 되겠다 했는데..
TextFieldDefaultsDecorationBox라서 그런지 저걸 사용하게 되면 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에 대해서 정확히 알게 되었다^^

profile
고생끝에롹이온다

0개의 댓글