https://kotlinlang.org logo
#compose
Title
# compose
l

Lilly

01/05/2022, 1:24 PM
I would like to have the
TextFieldColors
to apply the color for
onSecondary
instead of
onPrimary
. I tried with
TextStyle.color
or wrapping it in a Surface and setting contentColor but nothing works. The text/label/indicator color is always black. My
onSecodary
color is white.
Copy code
Column(modifier = Modifier.padding(8.dp)) {
            TextField(
                modifier = Modifier.fillMaxWidth(),
                value = password,
                onValueChange = { password = it },
                label = { Text("Password") },
                visualTransformation = PasswordVisualTransformation(),
                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
           )
}
Any ideas?
b

Bradleycorn

01/05/2022, 3:52 PM
In our app, we use custom colors on our TextFields as well. I wrote a wrapper composable that sets the colors on the TextField like this:
Copy code
@Composable
fun ThemedTextField(
        label: String,
        modifier: Modifier = Modifier,
        textFilter: (String, String) -> String = {_, new -> new },
        backgroundColor: Color = MaterialTheme.colors.primary,
        keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
        visualTransformation: VisualTransformation = VisualTransformation.None,
        interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }) {

    val contentColor = contentColorFor(backgroundColor = backgroundColor)
    
    // Many of these values are the same as the default, just using contentColor instead 
    // of the default text field color. 
    val colors = TextFieldDefaults.textFieldColors(
        textColor = contentColor,
        backgroundColor = backgroundColor,
        cursorColor = contentColor,
        focusedIndicatorColor = contentColor.copy(alpha = ContentAlpha.high),
        unfocusedIndicatorColor = contentColor.copy(alpha = TextFieldDefaults.UnfocusedIndicatorLineOpacity),
        leadingIconColor = contentColor.copy(alpha = TextFieldDefaults.IconOpacity),
        trailingIconColor = contentColor.copy(alpha = TextFieldDefaults.IconOpacity),
        focusedLabelColor = contentColor.copy(alpha = ContentAlpha.high),
        unfocusedLabelColor = contentColor.copy(alpha = ContentAlpha.medium),
        placeholderColor = contentColor.copy(alpha = ContentAlpha.medium)
    )

    TextField(
            label = { Text(text = label, style = MaterialTheme.typography.body1, maxLines = 1) },
            maxLines = maxLines,
            singleLine = maxLines == 1,
            shape = RectangleShape,
            colors = colors,
            interactionSource = interactionSource,
            keyboardOptions = keyboardOptions,
            visualTransformation = visualTransformation,
            modifier = modifier
    )
}
l

Lilly

01/05/2022, 4:27 PM
@Bradleycorn thanks for sharing. It would be unfortunate if setting all/*or some of the colors* manually would be the only solution. I expected to find something more elegant, something like a switch to mimic that the background is in secondary color and so the content color too
b

Bradleycorn

01/05/2022, 5:31 PM
@Lilly Well, you don’t have to set them all …. if you only want to set a few, and let the rest use their defaults, you could do that:
Copy code
// Just set the text and cursor color, and use material defaults for everything else
val myColors = TextFieldDefaults.textFieldColor(textColor = Color.Red, cursorColor = Color.Blue)

TextField(colors = myColors)
l

Lilly

01/05/2022, 5:32 PM
Anyway, I would expect that this works:
Copy code
MyTheme() {
        Surface(
            color = MaterialTheme.colors.secondary,
            contentColor = MaterialTheme.colors.contentColorFor(MaterialTheme.colors.secondary)
        ) {

            var text by remember { mutableStateOf("") }

            TextField(
                modifier = Modifier.fillMaxWidth(),
                value = text,
                onValueChange = { text = it },
                label = { Text("Username") }
            )
        }
    }
It seems the TextField composable is immune against theming. I might file a bug?
b

Bradleycorn

01/05/2022, 5:37 PM
I think it’s just that the Material Text Field has very specific guidelines, that include using certain colors from the theme. My guess is that the Dev team would say, “if you want a customized text field, use the
BasicTextField
composable” In our case, we want everything the material text field provides, just with some different coloring, so it was easiest to just create and pass in the color scheme that we wanted.
l

Lilly

01/05/2022, 5:39 PM
Possible. I will go with setting them manually for now. Thanks for your time :)
b

Bradleycorn

01/05/2022, 5:40 PM
Also, as you can see from my initial example, there are a lot of colors in a
TextField
.. if it was going to use the
LocalContentColor
to build itself, which color does it use for that? The text? the cursor? the indicator (outline/underline)? Whichever color it uses LocalContentColor for, what does it set the OTHER colors to? There’s no way to know. So, they probably just said, “let’s stick with the material guideline colors”, and if the dev wants to use different colors, we’ll expose a colors property they can set.
It looks like by default, it DOES use LocalContentColor … for the
textColor
. Here’s the defaults:
Copy code
fun textFieldColors(
        textColor: Color = LocalContentColor.current.copy(LocalContentAlpha.current),
        disabledTextColor: Color = textColor.copy(ContentAlpha.disabled),
        backgroundColor: Color = MaterialTheme.colors.onSurface.copy(alpha = BackgroundOpacity),
        cursorColor: Color = MaterialTheme.colors.primary,
        errorCursorColor: Color = MaterialTheme.colors.error,
        focusedIndicatorColor: Color =
            MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
        unfocusedIndicatorColor: Color =
            MaterialTheme.colors.onSurface.copy(alpha = UnfocusedIndicatorLineOpacity),
        disabledIndicatorColor: Color = unfocusedIndicatorColor.copy(alpha = ContentAlpha.disabled),
        errorIndicatorColor: Color = MaterialTheme.colors.error,
        leadingIconColor: Color =
            MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
        disabledLeadingIconColor: Color = leadingIconColor.copy(alpha = ContentAlpha.disabled),
        errorLeadingIconColor: Color = leadingIconColor,
        trailingIconColor: Color =
            MaterialTheme.colors.onSurface.copy(alpha = IconOpacity),
        disabledTrailingIconColor: Color = trailingIconColor.copy(alpha = ContentAlpha.disabled),
        errorTrailingIconColor: Color = MaterialTheme.colors.error,
        focusedLabelColor: Color =
            MaterialTheme.colors.primary.copy(alpha = ContentAlpha.high),
        unfocusedLabelColor: Color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium),
        disabledLabelColor: Color = unfocusedLabelColor.copy(ContentAlpha.disabled),
        errorLabelColor: Color = MaterialTheme.colors.error,
        placeholderColor: Color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium),
        disabledPlaceholderColor: Color = placeholderColor.copy(ContentAlpha.disabled)
    )
l

Lilly

01/05/2022, 5:47 PM
Yeah I understand what you mean. But sad that they didn't group the colors 😕 I'm also inspecting the source code
I just want the label, text, inidcator and icon in white while the rest keeps default. Would be cool if they would have grouped them, so you only have to set one color to change them
b

Bradleycorn

01/05/2022, 5:52 PM
yeah i see what you mean. You could write your own function to do that. It could be useful if you need to show textfields on different backgrounds and use a consistent coloring scheme.
Could even make it an extension on the Material Theme if you want…
Copy code
@Composable
fun MaterialTheme.textFieldColors(baseColor: Color): TextFieldColors = TextFieldDefaults.textFieldColors( 
   .. set the colors you want here ... 
)
l

Lilly

01/05/2022, 6:55 PM
Good point. You can also overwrite the Theme for the single composable but you will still have to set the text color with either
LocalContentColor
or via
TextStyle
, so not an appropriate solution.
@Bradleycorn One last question. When I start the interactive mode of the preview I'm not able to tap into the textfield and no label animation happens. Is this normal behavior?
b

Bradleycorn

01/05/2022, 8:25 PM
yeah I think so. On mine, I ended up creating a preview that contains several fields, with different `value`s so I could see it in various states .. one empty, one with text, one in an error state … unfortunately there doesn’t seem to be a good way to preview focused states
👍 1
c

Colton Idle

01/06/2022, 3:13 AM
WHenever I have one offs like this I jsut create a one off theme and then everything typically works. Much less code. It's what one of the official compose samples uses. I think @nickbutcher mentioned in a video that you should consider it like a theme overlay in legacy android.
159 Views