Jetpack Compose 使用自定义主题覆盖库中主题的部分内容

问题描述 投票:0回答:1

我正在努力为我们的应用程序创建一个库,旨在容纳所需的所有视图组件。该库还需要有一个自定义主题。特别是对于颜色和字体,因为使用该库的每个应用程序都将具有完全自定义的颜色和字体。

当我想创建这个主题时,我的问题出现了。如果我将主题和所有颜色分配保留在库中,效果很好,但我需要能够更改客户端应用程序中每个主题变量的颜色。

对于这个例子,假设我想在对话框中使用自定义颜色定义操作栏的不同部分。

我尝试通过 CompositionLocalProvider 来完成此操作,只要我保留在库中定义的颜色(每种颜色定义如下,与 https://m3.material.io/theme-builder#/custom 相同),它就可以正常工作用品。

val md_theme_light_primary = Color(0xFF6750A4)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)

真正的症结现在出现了。假设我已经在我的库中定义了颜色DialogActionBarText。在使用该库的每个客户端应用程序中,是否有任何方法可以仅公开定义的颜色变量来设置它们?下面的小示例片段

/** Colors */
class TestColors(
    dialogActionBarColor: Color,
    isLight: Boolean
) {
    var dialogActionBarColor by mutableStateOf(dialogActionBarColor)
    var isLight by mutableStateOf(isLight)

    fun copy(
        dialogActionBarColor: Color = this.dialogActionBarColor,
        isLight: Boolean = this.isLight
    ): TestColors = TestColors(
        dialogActionBarColor,
        isLight
    )
    fun updateColorFrom(other: TestColors) {
        dialogActionBarColor = other.dialogActionBarColor
    }
}

fun getLightColors(): TestColors = TestColors(
    dialogActionBarColor = dialogActionBarLight,
    isLight = true
)

fun getDarkColors(): TestColors = TestColors(
    dialogActionBarColor = dialogActionBarDark,
    isLight = true
)

val dialogActionBarLight: Color = Color(0xFFAABBCC)
val dialogActionBarDark: Color = Color(0xFF112233)

val LocalColors = staticCompositionLocalOf{ getLightColors() }

/** Fonts */

private val myFont = FontFamily(
    Font(R.font.open_sans_regular, FontWeight.Normal)
)

data class AppTypography(
    val h1: TextStyle = TextStyle(
        fontFamily = myFont,
        fontWeight = FontWeight.Normal,
        fontSize = 24.sp
    ),
    val h2: TextStyle = TextStyle(
        fontFamily = myFont,
        fontWeight = FontWeight.Normal,
        fontSize = 16.sp
    )
)
internal val LocalTypography = staticCompositionLocalOf { AppTypography() }

/** Theme */

object TestTheme {
    val colors: TestColors
        @Composable
        @ReadOnlyComposable
        get() = LocalColors.current
    val fonts: AppColors
        @Composable
        @ReadOnlyComposable
        get() = LocalColors.current

}
@Composable
fun TestTheme(
    colors: TestColors = TestTheme.colors,
    typography: TestTypography = TestTheme.fonts
    dimensions: TestDimensions...,
    content: @Composable () -> Unit
) {

    val rememberedColors = remember { colors.copy() }.apply { updateColorFrom(colors) }
    CompositionLocalProvider(
        LocalColors provides rememberedColors,
        LocalTypography provides typography,
        LocalDimensions provides dimensions
    ) {
        content()
    }
}

我想要的是将每个颜色变量dialogActionBarLight和-Dark公开给客户端应用程序,以便轻松设置它们,同时将其余主题和颜色设置保留在客户端应用程序之外。 同样的原则适用于每个客户端应用程序中可能不同的字体,因此我需要能够公开 myFont 变量。

我的目标是在客户端应用程序中可以实现最少的代码来定义颜色,因此仅创建一个重复的主题就违背了首先尝试将其分离的目的。

关于如何实现此目标或接近此目标的任何想法?

另一种说法是如何实现与使用 compose 中的库覆盖应用程序中的库中的 xml 资源值相同的结果?

android android-jetpack-compose android-theme android-jetpack-compose-material3
1个回答
0
投票

我认为你的做法是正确的。

您可以将颜色设置为数据类,并公开您希望客户端应用程序能够自定义的值,例如

data class TestColors(
    val mutableColor1: Color = Color.Red,
    val mutableColor2: Color = Color.White,
    val mutableColor3: Color = Color.Blue,
) {
    val immutableColor1 = Color.Red
    val immutableColor2 = Color.White
    val immutableColor3 = Color.Blue
}

然后使用本地合成,就像你一样。

但是您的主题无法像您拥有的那样工作,您无法访问

CompositionLocalProvider
之外的值。

您需要像这样重构它:

@Composable
fun TestTheme(
    colors: TestColors = TestColors(),
    typography: TestTypography = TestTypography(),
    dimensions: TestDimensions = TestDimensions(),
    content: @Composable () -> Unit
) {

    CompositionLocalProvider(
        LocalColors provides colors,
        LocalTypography provides typography,
        LocalDimensions provides dimensions
    ) {
        content()
    }
}

然后让客户端应用程序简单地自定义可变属性并直接使用您的主题:

@Composable
fun ClientApp() {
    val colors = TestColors(...)
    TestTheme(colors = colors) {
        ...
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.