Reputation: 18725
EDIT: Adding more detail - to make code complete:
I am having challenges applying theme colors to OutlinedTextFields
, after converting to the new M3 themes.
From what I can tell, there is no direct support for using the new design token colors (primaryContainer
, tertiary
, etc) when using the OutlinedTextField
.
Question: Is there a simple way to apply these colors universally?
Question: When I apply custom colors, they aren't all applied, and I am not sure why?
What I tried:
This is the function I use to create custom TextFieldColors
, and how I apply them:
@Composable
fun customTextColors(): TextFieldColors =
TextFieldDefaults.outlinedTextFieldColors(
textColor = MaterialTheme.colorScheme.onBackground,
disabledTextColor = MaterialTheme.colorScheme.onBackground,
backgroundColor = MaterialTheme.colorScheme.background,
cursorColor = MaterialTheme.colorScheme.onBackground,
errorCursorColor = MaterialTheme.colorScheme.error,
focusedBorderColor = MaterialTheme.colorScheme.primary,
unfocusedBorderColor = MaterialTheme.colorScheme.onBackground,
disabledBorderColor = MaterialTheme.colorScheme.onBackground,
errorBorderColor = MaterialTheme.colorScheme.error,
leadingIconColor = MaterialTheme.colorScheme.onBackground,
disabledLeadingIconColor = MaterialTheme.colorScheme.onBackground,
errorLeadingIconColor = MaterialTheme.colorScheme.error,
trailingIconColor = MaterialTheme.colorScheme.onBackground,
disabledTrailingIconColor = MaterialTheme.colorScheme.onBackground,
errorTrailingIconColor = MaterialTheme.colorScheme.error,
focusedLabelColor = MaterialTheme.colorScheme.primary,
unfocusedLabelColor = MaterialTheme.colorScheme.onBackground,
disabledLabelColor = MaterialTheme.colorScheme.onBackground,
errorLabelColor = MaterialTheme.colorScheme.error,
placeholderColor = MaterialTheme.colorScheme.onBackground,
disabledPlaceholderColor = MaterialTheme.colorScheme.primary,
)
then applying them in this way:
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material.icons.outlined.VisibilityOff
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.input.*
import com.myApp.demo.R
import com.myApp.demo.data.StaticData
import com.myApp.demo.ui.theme.card_corner_radius
import com.myApp.demo.ui.theme.grey_400
import com.myApp.demo.ui.theme.horizfull_verthalf
@Composable
fun NameTextInput(name: String, onNameInfoValid: (Boolean) -> Unit) {
// Name
val nameState = remember { mutableStateOf(TextFieldValue(name)) }
val nameString = stringResource(R.string.name)
val nameLabelState = remember { mutableStateOf(nameString) }
val isNameValid = if (nameState.value.text.length >= 5) {
nameLabelState.value = nameString
onNameInfoValid(true)
true
} else {
nameLabelState.value = stringResource(R.string.name_error)
onNameInfoValid(false)
false
}
OutlinedTextField(
shape = RoundedCornerShape(card_corner_radius),
value = nameState.value,
singleLine = true,
onValueChange = { if (it.text.length <= 30) nameState.value = it },
isError = !isNameValid,
label = { Text(nameLabelState.value) },
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
capitalization = KeyboardCapitalization.Words
),
colors = customTextColors(), // <-- Here is where colors are set!
modifier = Modifier
.fillMaxWidth()
.padding(horizfull_verthalf)
)
}
They aren't all being applied.
I see the focusedBorderColor
set correctly, but I don't see focusedLabelColor
being applied correctly (in this case RED is the correct primary color to be applied, so I would want to see the Label also be RED)
Also error is border is working, but not for the other attributes:
Here is my Theme setup:
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
private val DarkColorPalette = darkColorScheme(
primary = grey_700,
onPrimary = white_desat,
tertiary = grey_600,
secondary = amer_blue, // TODO desat
onSecondary = grey_500,
surface = black_pure,
onSurface = white_desat,
surfaceVariant = grey_800,
onSurfaceVariant = white_desat,
error = orange_700,
onError = orange_700
)
private val LightColorPalette = lightColorScheme(
primary = amer_red,
onPrimary = white_pure,
tertiary = amer_blue_50,
secondary = amer_blue,
onSecondary = grey_500,
surface = white_pure,
onSurface = black_pure,
surfaceVariant = white_pure,
onSurfaceVariant = black_pure,
error = orange_500,
onError = orange_500,
errorContainer = orange_500,
onErrorContainer = orange_500
/* Other default colors to override
background = Color.White,
onBackground = Color.Black,
*/
)
@Composable
fun ComposeTemplateTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colorScheme = colors,
typography = DemoTypography,
content = content
)
}
Finally to make this example complete, here is how I call the Composable in the first place:
NameTextInput(name = personalInfo.name, onNameInfoValid = { isNameValidState.value = it })
...and the versions I am using
appCompatVersion = '1.3.1'
activityComposeVersion = '1.4.0'
composeVersion = '1.0.4'
composeNavigationVersion = '2.4.0-alpha06'
kotlinVersion = '1.5.31'
ktlint_version = "0.42.1"
ktxVersion = '1.7.0'
lifecycleVersion = '2.3.0'
materialVersion = '1.5.0-alpha05'
Upvotes: 2
Views: 7613
Reputation: 14787
This seems crazy. But this is what happens.
There seems to be some style conflict between Material 2 and Material 3 . (apparently obvious I guess).
Using
import androidx.compose.material3.Text
But when using
import androidx.compose.material.Text
This one line change solved the issue.
My complete material imports if needed.
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Clear
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
Additional helpful info,
I am maintaining complete 2 sets of resources.
This might help for components that are not supported in M3 yet.
Use appropriate imports in the composable.
We can use complete imports if a particular composable has both M2 and M3 components.
private val Material2DarkColorPalette = darkColors(
primary = Primary,
...
)
private val Material2LightColorPalette = lightColors(
primary = Primary,
...
)
private val LightColorPalette = lightColorScheme(
primary = Primary,
...
)
private val DarkColorPalette = darkColorScheme(
primary = Primary,
...
)
@Composable
fun Material2AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit,
) {
val colors = if (darkTheme) {
Material2DarkColorPalette
} else {
Material2LightColorPalette
}
androidx.compose.material.MaterialTheme(
colors = colors,
typography = Material2Typography,
shapes = Shapes,
content = content
)
}
@Composable
fun Material3AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit,
) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colorScheme = colors,
typography = Typography,
content = content
)
}
@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit,
) {
Material2AppTheme(
darkTheme = darkTheme,
content = content,
)
}
Upvotes: 4