当前位置: 首页 > 知识库问答 >
问题:

Jetpack Compose:如何通过编程将主题从浅色模式更改为深色模式onClick

陆宇航
2023-03-14

TL;DR在单击时更改主题并在明暗主题之间重新组合应用程序。

你好我有一个有趣的问题,我一直在努力解决,希望能得到一些帮助。我试图实现一个设置屏幕,让用户改变应用程序的主题(选择黑暗,光明,或自动匹配系统设置)。

我在选择调色板时通过调用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组件中省略了一些代码,在这个过程中可能遗漏了一些闭包语法。

共有3个答案

廖招
2023-03-14

根据文档,处理由用户操作触发的主题更改(即通过自定义构建设置选择系统主题以外的主题)的官方方法是使用

AppCompatDelegate.setDefaultNightMode()

仅此调用就可以处理大多数事情,包括重新启动任何活动(因此,重新组合)。为此,我们需要:

  • 调用setContent来扩展appcompactivity的活动
@Composable
fun CustomTheme(
  isDark: Boolean = isNightMode(),
  content: @Composable () -> Unit
) {
  MaterialTheme(
    colors = if (darkTheme) DarkColors else LightColors,
    content = content
  )
}

@Composable
private fun isNightMode() = when (AppCompatDelegate.getDefaultNightMode()) {
    AppCompatDelegate.MODE_NIGHT_NO -> false
    AppCompatDelegate.MODE_NIGHT_YES -> true
    else -> isSystemInDarkTheme()
}

这是很好的,因为它避免了在活动中获取此值的需要,只是为了将其传递给带有CustomTheme(isDard=isDard)的主题。

本文将详细介绍以上所有内容。

慕容康安
2023-03-14

如果您需要一个按钮/开关来更改主题并将其作为设置持久化,您也可以通过使用Jetpack数据存储(推荐)或SharedReferences来实现这一点,在MainActivity中获取主题状态,并将其传递给您的主题可编程序,无论您想在哪里修改它。

您可以在这个GitHub repo中找到一个完整的工作示例。

本例使用单例和Hilt作为依赖项,适用于您想要存储的所有首选项。

厉念
2023-03-14

Jetpack主题代码实验室中显示了一种可能性,即通过输入参数设置深色模式,以确保在参数更改时重新组合主题:

@Composable
fun CustomTheme(
  darkTheme: Boolean = isSystemInDarkTheme(),
  content: @Composable () -> Unit
) {
  MaterialTheme(
    colors = if (darkTheme) DarkColors else LightColors,
    content = content
  )
}

在你的主活动中,你可以观察到你的视图模型的变化,并将它们传递给你的自定义主题:

val darkTheme = themeViewModel.darkTheme.observeAsState(initial = true)

CustomTheme(darkTheme.value){
//yourContent
}

通过这种方式,您的撰写预览可以简单地在深色主题中设置样式:

@Composable
private fun DarkPreview() {
    CustomTheme(darkTheme = true) {
        content
    }
}
 类似资料:
  • 我创建了一个暗/亮主题切换器,我发现的问题是当我在输入域输入任何信息时,当网站在暗模式下时,输入域内的文本显示为黑色,我如何改变它,在亮模式下保持黑色文本颜色,在暗模式下保持白色文本颜色。 这是我的CSS为光明/黑暗模式。如何为黑暗模式添加不同的文本颜色? 我试图用这段代码,但它在黑暗和光明模式下都发生了变化。 编辑:我从下面的回答中添加内容。它现在工作只有一个问题,当我改变到光模式时,输入文本颜

  • 关于这个话题有很多帖子,但我找不到一个有用的。 我有一个未嵌入导航控制器的视图控制器。我想把状态栏的颜色改成黑色。 如何在Swift 3中设置状态栏样式 改变行info.plist查看基于控制器的状态栏外观并将其设置为NO didFinishLaunchingwith Options中appDelegate.swift的更改

  • 使用elementui,通过1个按钮修改深色浅色样式,深浅颜色怎么写?

  • 在我的一个应用程序中,我为状态栏设置了半透明的颜色。 在前两个屏幕上,它显示如预期的,但在第三个屏幕上,它将改变状态栏的样式。它将转换为灰色半透明。 预期屏幕样本: 本期: 我已经完成了与在应用程序中显示灯光内容状态栏相关的所有更改。 将状态栏显示为 还可以向plist添加标志,如下所述。 但在我的应用程序中仍然存在上述问题。 任何帮助都将不胜感激。

  • 我已经尝试了这个解决方案,并且在XML中工作得很好,但是我如何通过代码来做同样的事情呢? 事实上,我想改变编辑文本(主题:标签,文本颜色,行颜色)按一个按钮。

  • 我已经读过一些关于颜色的线程,但所有这些线程都必须通过style.xml进行设置。 现在我用这个来确定颜色。 是否可以不使用XML,例如使用代码来更改SwitchCompat/Checkbox的颜色?