TL;DR更改主题,并在亮主题和暗主题之间重新组合应用程序onClick。
你好!我有一个有趣的问题,我一直在努力弄清楚,并希望得到一些帮助。我正在尝试实现一个设置屏幕,让用户改变应用程序的主题(选择黑暗,光明,或自动匹配系统设置)。
我在选择调色板时通过调用isSystemInDarkTheme()函数成功地动态设置了主题,但在点击一个按钮时重新组合应用的明暗主题时却很吃力。
我现在的策略是创建一个主题模型,它从用户实际选择主题的设置组件中提升状态。然后,这个主题模型向自定义主题公开一个主题状态变量(围绕材质主题),以决定是选择浅色还是深色调色板。
布景主题
@Composable
fun CustomTheme(
themeViewModel: ThemeViewModel = viewModel(),
content: @Composable() () -> Unit,
) {
val colors = when (themeViewModel.theme.value.toString()) {
"Dark" -> DarkColorPalette
"Light" -> LightColorPalette
else -> if (isSystemInDarkTheme()) DarkColorPalette else LightColorPalette
}
MaterialTheme(
colors = colors,
typography = typography,
shapes = shapes,
content = content
)
}
主题模型和状态变量
class ThemeViewModel : ViewModel() {
private val _theme = MutableLiveData("Auto")
val theme: LiveData<String> = _theme
fun onThemeChanged(newTheme: String) {
when (newTheme) {
"Auto" -> _theme.value = "Light"
"Light" -> _theme.value = "Dark"
"Dark" -> _theme.value = "Auto"
}
}
}
组件(UI)代码
@Composable
fun Settings(
themeViewModel: ThemeViewModel = viewModel(),
) {
...
val theme: String by themeViewModel.theme.observeAsState("")
...
ScrollableColumn(Modifier.fillMaxSize()) {
Column {
...
Card() {
Row() {
Text(text = theme,
modifier = Modifier.clickable(
onClick = {
themeViewModel.onThemeChanged(theme)
}
)
)
}
}
}
非常感谢您的时间和帮助!***我在UI组件中省略了一些代码,可能是我在此过程中遗漏了一些闭包语法。
5条答案
按热度按时间pn9klfpd1#
如Jetpack主题化代码实验室所示,一种可能性是通过输入参数设置darkmode,这确保了当参数改变时,主题将被重新组合:
在mainActivity中,您可以观察viewModel的变化,并将其传递给customTheme:
这样,您的合成预览就可以简单地以暗色主题进行样式化:
u5i3ibmn2#
如果您希望按钮/开关更改主题并使其作为设置持久化,您也可以通过使用Jetpack DataStore(推荐)或SharedPreferences来实现这一点,在MainActivity中获取主题状态并将其传递给您的Theme组合对象,以及您希望修改它的任何位置。
您可以在GitHub repo中找到
SharedPreferences
的完整工作示例。此示例使用
Singleton
和Hilt作为依赖项,并且对您要存储的所有首选项都有效。hyrbngr73#
基于the docs,处理由用户操作触发的主题更改(即,通过自定义构建的设置选择主题而不是系统主题)的正式方式是使用
这个调用本身就可以处理大多数事情,包括重新启动任何活动(因此,重新组合)。
setContent
以扩展AppCompatActvity
的活动AppCompatDelegate
)CustomTheme
还应考虑用户的defaultNightMode
首选项的值:这很好,因为它避免了在Activity中获取此值,然后通过
CustomTheme(isDark = isDark)
将其传递给主题的需要。This article执行上述所有操作,提供更多详细信息。
jaxagkaj4#
这可能不是推荐的方法,但有一种选择是使用recreate方法(自API级别11起可用)。
为了在Activity外部和可组合对象内部使用它,您可以传递函数调用。
在视图中模型
ekqde3dh5#
我只是用一个简单的模型做出来的。
声明公共变量isUiModeDark
然后,在主题的Lambda中:
现在如何调用recomposition?很简单,只需在设置中更改isUiModeDark的值。
至于为什么这样做,只要阅读MutableState上的文档并记住。基本上,MutableState值的任何更改都会导致重新组合。Live数据或任何其他替代项都不起作用,除非它们是State类型的派生项。可组合项基本上只是订阅了对MutableState或State类的任何派生项所做的更改。