【问题标题】:Applying Material3 colors to OutlinedTextField in Jetpack Compose在 Jetpack Compose 中将 Material3 颜色应用于 OutlinedTextField
【发布时间】:2021-12-15 04:54:10
【问题描述】:

编辑:添加更多细节 - 使代码完整:

在转换为新的 M3 主题后,我在将主题颜色应用到 OutlinedTextFields 时遇到了挑战。

据我所知,在使用 OutlinedTextField 时,没有直接支持使用新的设计标记颜色(primaryContainertertiary 等)。

问题:有没有一种简单的方法可以通用地应用这些颜色?
问题:当我应用自定义颜色时,它们并没有全部应用,而且我不知道为什么?

我尝试了什么:

这是我用来创建自定义TextFieldColors 的函数,以及我如何应用它们:

@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,
    )

然后以这种方式应用它们:

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)
    )
}

它们并没有全部被应用。

我看到 focusedBorderColor 设置正确,但我没有看到 focusedLabelColor 被正确应用(在这种情况下,红色是要应用的正确 primary 颜色,所以我想看到标签也是红色的)

还有错误是 border 正在工作,但不适用于其他属性:

这是我的主题设置:

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
    )
}

最后,为了使这个示例完整,我首先是这样调用 Composable 的:

NameTextInput(name = personalInfo.name, onNameInfoValid = { isNameValidState.value = it })

...以及我正在使用的版本

        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'

【问题讨论】:

  • 您的代码正确更改了我的标签颜色。请提供minimal reproducible example
  • 工作得很好。请检查您的进口。如果您正在部分迁移,可能会有一些带有 material3 和一些较旧的导入。特别是检查主题、排版、形状等文件。我在第一次运行时错过了这些文件。
  • 另外,注意材料3没有TextField,所以TextField仍然来自材料2。Compose Material 3 1.0.0-alpha01 release notes
  • 我知道 TextField 仍然来自 M2,我认为这实际上是 still 在那个宇宙中(除了我现在使用的颜色名称来自 M3 颜色主题)。 @philipdukhov - 你是说你确实看到标签颜色正确,就像在我的图像中一样,错误文本会是橙色或“名称”会是红色?
  • @Booger 我没有检查错误,但名称肯定是红色的。

标签: android-jetpack-compose material-components-android


【解决方案1】:

这看起来很疯狂。但这就是发生的事情。

Material 2 和 Material 3 之间似乎存在一些风格冲突。 (我猜显然很明显)。

使用

import androidx.compose.material3.Text

但是在使用的时候

import androidx.compose.material.Text

这一行更改解决了问题。

如果需要,我的完整材料会导入。

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

其他有用的信息,

我正在维护完整的 2 套资源。
这可能对 M3 尚不支持的组件有所帮助。
在可组合中使用适当的导入。
如果特定的可组合项同时具有 M2 和 M3 组件,我们可以使用完全导入。

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,
    )
}

【讨论】:

  • 这确实为我解决了这个问题,并解释了为什么其他人看到这个工作......我在更改导入时能够看到正确的标签颜色。谢谢你。非常值得赏金!
  • 我没有看到其他元素发生变化(如尾随图标颜色等)——这真是太糟糕了。 M2 和 M3 之间的导入肯定会在一段时间内成为挑战(只要我们需要同时支持两者)。
  • 很高兴,它有效。 :)
  • 是的,您可以尝试维护2套主题和其他资源。这对我来说似乎很有效。
  • 但我发送的颜色值不是来自我的主题,它们已被解析并以TextFieldColors 发送 - 我认为 M3 文本(我不知道存在)不是功能完整(这可能是这些颜色不起作用的原因)。但是切换到 M2 Text 确实让我更接近,所以这肯定是成功的。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2022-11-06
  • 2022-10-21
  • 1970-01-01
  • 2022-10-05
  • 2023-02-12
  • 1970-01-01
  • 2022-11-06
  • 2022-11-09
相关资源
最近更新 更多