[Android] Jetpack Compose에서 TextField는 어떻게 커스텀 할까?

검색이나 값을 사용자로부터 입력받아야 하는 경우 xml에서는 EditText를 사용해 왔습니다.

Compose에서는 TextField라는 것을 사용합니다.

TextField는 어떻게 커스텀할 수 있을까요?

 


 

 

1. TextField

먼저, TextField에 대해 간단히 알아보도록 하겠습니다.

@Composable
fun TextField(
    value: TextFieldValue,
    onValueChange: (TextFieldValue) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    label: @Composable (() -> Unit)? = null,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions(),
    singleLine: Boolean = false,
    maxLines: Int = Int.MAX_VALUE,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = TextFieldDefaults.TextFieldShape,
    colors: TextFieldColors = TextFieldDefaults.textFieldColors()
)

EditText와 비슷하게 placeholder, enabled, maxLines 등 다양한 기능을 제공합니다.

 

TextField는 위 사진처럼 Material 디자인을 기본으로 하기 때문에 다양한 모양의 TextField를 표현하기에는 제한적입니다.

그렇다면 커스텀해야 하는 경우 어떻게 해야 할까요?

 

 

바로 foundation 아티팩트에 위치한 BasicTextField를 사용하여 다양하게 커스텀할 수 있습니다.

 

2. BasicTextField

BasicTextField 내부 코드를 살펴보도록 하겠습니다.

@Composable
fun BasicTextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = TextStyle.Default,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = false,
    maxLines: Int = Int.MAX_VALUE,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    cursorBrush: Brush = SolidColor(Color.Black),
    decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
        @Composable { innerTextField -> innerTextField() }
)

TextField와 크게 다르지 않지만 placeholder나 label 등은 보이지 않는 것을 보아 제공하지 않는 것을 확인할 수 있습니다.

하지만 맨 밑에 새롭게 추가된 인자도 있습니다. 바로 decorationBox인데요,

커스텀 하고 싶은 UI를 decorationBox에 구현할 수 있습니다!

 

 

 

그럼 간단한 예제와 함께 확인해 보도록 하겠습니다.

decorationBox = { innerTextField ->
            Row(
                modifier = Modifier
                    .padding(horizontal = 64.dp)
                    .fillMaxWidth()
                    .background(color = Color(0xFFD2F3F2), shape = RoundedCornerShape(size = 16.dp))
                    .padding(all = 16.dp),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                Icon(
                    imageVector = Icons.Default.Search,
                    contentDescription = "",
                    tint = Color.DarkGray,
                )
                Spacer(modifier = Modifier.width(width = 8.dp))
                innerTextField()
            }
        },

현재 decorationBox안을 보면, 텍스트를 입력할 수 있는 박스와 아이콘이 있도록 구현되어 있습니다. 그리고 decorationBox의 기본 인자인 innerTextField()를 마지막 줄에 적어주었습니다. innerTextField는 키보드 커서를 표시할 수 있도록 해주기 때문에 작성하지 않는 경우에는 키보드 커서가 노출되지 않습니다.

아래 결과물은 다음과 같습니다!

 

위에서 말했듯이 BasicTextField에는 placeholder 인자가 존재하지 않습니다. placeholder를 넣어주고 싶은 경우에는 어떻게 해야 할까요?

if (value.isEmpty()) {
	Text(
         text = "placeholder",
         fontSize = 18.sp,
         color = Color.LightGray,
  	)
}

위 코드처럼 textField안에 값이 비었는지 확인하여 간단하게 넣어줄 수 있습니다!

 

 

 

이제 다양한 디자인의 TextField를 구현해야 한다면 BasicTextField를 활용해 보는 것이 어떨까요?!😀😀