JetPack的定制主题构成
#kotlin #android #mobile #jetpackcompose

使用材料主题时,您无法完全反映品牌的颜色吗?还是物质主题听起来很无聊?还是您不希望您的应用程序成为某种刻板印象的Google应用程序?

即使Google推荐材料设计系统,您也可以创建自定义设计系统。但是,组成的组件是在MaterialTheme上构建的,因此,如果要创建自定义设计系统,则还必须创建自定义组合。

创建自定义类

首先,您需要创建自定义数据类,例如自定义颜色,惯性图和自定义效果。

@Immutable
data class CustomColors(
    val container: Color,
    val content: Color,
    val background: Color,
    val onBackground: Color
)

@Immutable
data class CustomTypography(
    val title: TextStyle,
    val body: TextStyle,
    val label: TextStyle
)

@Immutable
data class CustomElevation(
    val default: Dp,
    val pressed: Dp
)

koude1注释告诉撰写编译器,此对象是可以进行优化的,因此如果不使用它,可能会有不必要的重新组合可能会触发。

此外,创建自定义主题的一件好事是,您可以根据自己的需求定义属性而不与材料设计系统联系在一起。

您刚刚为自定义主题创建了类,现在您将看到如何使用它们。

创建组合局值

创建一个可以使用CompositionLocalProvider提供的CompositionLocal键。

compositionLocalOf不同,staticCompositionLocalOf的读取不是由作曲家跟踪的,并且更改CompositionLocalProvider呼叫中提供的值会导致整个内容被重新计算,而不仅仅是在组成中使用本地值的地方。但是,缺乏跟踪使staticCompositionLocalOf在极不可能或永远不会改变的值时更有效。例如,Android上下文,字体加载程序或类似的共享值不太可能在CompositionLocalProvider内容中的组件更改,并且应该考虑使用staticCompositionLocalOf。颜色或其他主题(例如价值)可能会改变甚至是动画的;因此,应使用compositionLocalOf
staticCompositionLocalOf创建了一个ProvidableCompositionLocal,可以在呼叫CompositionLocalProvider中使用。类似于MutableList vs. List,如果将钥匙公开为CompositionLocal而不是ProvidableCompositionLocal,则可以使用CompositionLocal.current读取,但不能重新提供。

val LocalCustomColors = staticCompositionLocalOf {
    CustomColors(
        container = Color.Unspecified,
        content = Color.Unspecified,
        background = Color.Unspecified,
        onBackground = Color.Unspecified
    )
}

val LocalCustomTypography = staticCompositionLocalOf {
    CustomTypography(
        title = TextStyle.Default,
        body = TextStyle.Default,
        label = TextStyle.Default
    )
}

val LocalCustomElevation = staticCompositionLocalOf {
    CustomElevation(
        default = Dp.Unspecified,
        pressed = Dp.Unspecified
    )
}

创建自定义主题

创建CompositionLocal值后,您需要分配它们的实际值并为其提供CompositionLocalProvider。最后,您将能够通过创建CustomTheme对象访问这些提供的对象。

@Composable
fun CustomTheme(content: @Composable () -> Unit) {
    val colors = CustomColors(
        container = container,
        content = content,
        background = background,
        onBackground = onBackground
    )
    val elevation = CustomElevation(
        default = 0.dp,
        pressed = 0.dp
    )
    val typography = CustomTypography(
        title = TextStyle(
            fontSize = 32.sp,
            fontWeight = FontWeight.Bold
        ),
        body = TextStyle(fontSize = 20.sp),
        label = TextStyle(fontSize = 16.sp)
    )
    CompositionLocalProvider(
        LocalCustomColors provides colors,
        LocalCustomTypography provides typography,
        LocalCustomElevation provides elevation,
        content = content
    )
}

object CustomTheme {
    val colors: CustomColors
        @Composable
        get() = LocalCustomColors.current
    val typography: Typography
        @Composable
        get() = LocalCustomTypography.current
    val elevation: CustomElevation
        @Composable
        get() = LocalCustomElevation.current
}

请记住,您需要创建给定制类别类的颜色值。您可以通过将它们定义为UI/theme/color.kt。

来使用它们

黑暗主题集成

即使您不使用材料设计系统,也可以通过一些更改轻松地集成黑暗主题。

添加配色方案

您需要定义2种不同的配色方案,因为即使原色不变,背景和倒置的颜色也会改变。

val lightColors = CustomColors(
        container = light_container,
        content = light_content,
        background = light_background,
        onBackground = light_onBackground
)

val darkColors = CustomColors(
        container = dark_container,
        content = dark_content,
        background = dark_background,
        onBackground = dark_onBackground
)

根据系统主题调整颜色

@Composable
fun CustomTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = when {
        darkTheme -> darkColors
        else -> lightColors
    }
    . . .
}

将设计应用于自定义组合

如果您还记得,我在文章开头提到,如果您想使用自定义主题,则需要创建组合。组合基于MaterialTheme。也就是说,如果您使用的是自定义主题,并且不将此主题分配给他们,他们仍将使用MaterialTheme

您可以创建自定义按钮并在代码中使用它。

@Composable
fun CustomButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    content: @Composable RowScope.() -> Unit
) {
    Button(
        onClick = onClick,
        modifier = modifier,
        colors = ButtonDefaults.buttonColors(
            containerColor = CustomTheme.colors.container,
            contentColor = CustomTheme.colors.content
        ),
        elevation = ButtonDefaults.buttonElevation(
            defaultElevation = CustomTheme.elevation.default,
            pressedElevation = CustomTheme.elevation.pressed
        ),
        content = {
            // The text style inside the button can also be 
            // applied this way.
            ProvideTextStyle(CustomTheme.typography.label) {
                content()
            }
        }
    )
}

您应该记住,以这种方式定义的自定义组合的限制受您给出的参数的限制。如果您需要更多自定义,则必须定义相关参数。

为深色主题兼容创建自定义表面

我们只是为轻型主题定义了单独的背景颜色。通过定义自定义表面,您可以具有背景颜色更改以适合这些颜色。

@Composable
fun CustomSurface(
    modifier: Modifier = Modifier,
    content: @Composable () -> Unit
) {
    Surface(
        modifier = modifier.fillMaxSize(),
        color = CustomTheme.colors.background,
        content = content
    )
}

您可以使用background()修饰符为没有颜色属性的组合设置背景颜色,例如下拉列表。

结论

在使用Compose开发应用程序时,创建自定义设计系统是一个不错的选择,但它带来了很多挑战。这就是为什么我说不要忘记您必须在选择选择时自定义每个组合的事实。

如果您有任何疑问,请随时发表评论。您还可以找到官方文件here