androidkotlinandroid-jetpack-composeandroid-jetpack-compose-material3android-compose-textfield

Optional to pass leadingIcon, trailingIcon parameters to own OutlinedTextField


I'm trying to create default parameters via leadingIcon: @Composable () -> Unit= {} or trailingIcon: @Composable (() -> Unit)? = null, but ran into a problem. An empty form is created on the TextField and for this reason the text is shifted closer to the center.

What I want:

What I have:

This is the code:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun OutlinedTextField(
    text: String,
    onValueChange: (String) -> Unit,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    leadingIcon: @Composable () -> Unit = {},
    trailingIcon: @Composable (() -> Unit)? = null,
) {
    BasicTextField(
        value = text,
        onValueChange = { onValueChange(it) },
    ) { innerTextField ->
        OutlinedTextFieldDefaults.DecorationBox(
            leadingIcon = { leadingIcon() },
            trailingIcon = { if (trailingIcon != null) trailingIcon() },
            value = text,
            innerTextField = innerTextField,
            enabled = true,
            singleLine = true,
            visualTransformation = VisualTransformation.None,
            interactionSource = interactionSource,
        )
    }
}

@Preview
@Composable
fun OutlinedTextFieldPreview() {
    OutlinedTextField(
        text = "Hello World",
        onValueChange = { },
        leadingIcon = { },
        trailingIcon = null,
    )
}

Solution

  • leadingIcon and trailingIcon are both optional parameters on OutlinedTextFieldDefaults.DecorationBox. They are declared like this:

    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    

    You can either omit these parameters or pass null, both will have the same result. The important thing is that you pass null if you do not want any icon or an empty placeholder displayed. Using { leadingIcon() } is not null, it is an empty composable. The same goes for { if (trailingIcon != null) trailingIcon() }: As soon as you use curly braces {} you create a composable. You need to pass null instead.

    When you declare the parameters of your own OutlinedTextField the same way as the DecorationBox does then you can just pass them on like this:

    OutlinedTextFieldDefaults.DecorationBox(
        leadingIcon = leadingIcon,
        trailingIcon = trailingIcon,
        // ...
    )
    

    Now when you omit either parameter it will free up the space the icon would have taken, just as expected.