我正在努力为我们的应用程序创建一个库,旨在容纳所需的所有视图组件。该库还需要有一个自定义主题。特别是对于颜色和字体,因为使用该库的每个应用程序都将具有完全自定义的颜色和字体。
当我想创建这个主题时,我的问题出现了。如果我将主题和所有颜色分配保留在库中,效果很好,但我需要能够更改客户端应用程序中每个主题变量的颜色。
对于这个例子,假设我想在对话框中使用自定义颜色定义操作栏的不同部分。
我尝试通过 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 资源值相同的结果?
我认为你的做法是正确的。
您可以将颜色设置为数据类,并公开您希望客户端应用程序能够自定义的值,例如
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) {
...
}
}