【问题标题】:Jetpack Compose. Force switch night/notnight resources喷气背包组成。强制切换夜间/非夜间资源
【发布时间】:2021-10-08 11:52:40
【问题描述】:

最初,我的应用程序的主题遵循系统的主题,为方便起见,我为浅色和深色主题创建了可绘制资源。然后我实现了无论系统主题如何都可以手动更改主题的能力,但显然可绘制资源与系统主题或其他东西相关联。有没有办法以某种方式在夜间和非夜间可绘制资源之间强制切换?

【问题讨论】:

    标签: android android-resources android-jetpack-compose android-theme


    【解决方案1】:

    找到了解决办法,如有错误请指正。

    1. 从 AppCompatActivity 继承我们的 Activity 而不是 ComponentActivity

    2. 使用 AppDelegateCompat.setDefaultNightMode() 告诉应用我们要使用哪个主题

    3. 调用delegate.applyDayNight()

       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           // Getting user's saved selection
           appTheme.value = runBlocking(Dispatchers.IO) {
               getSavedAppTheme(context)
           }
           // Telling the application which mode to use
           when (appTheme.value) {
               AppTheme.SYSTEM_THEME -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
               AppTheme.NIGHT_THEME  -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
               AppTheme.LIGHT_THEME  -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
           }
           delegate.applyDayNight()
           setContent {
               MyAppTheme {
                   MyAppComposable()
               }
           }
       }
      

    处理用户选择:

        suspend fun setAppTheme(context: Context, theme: AppTheme) {
            // Saving selection to cache 
            saveAppTheme(context, theme)
            // Applying selection
            appTheme.value = theme
            // Telling the application which mode to use
            when (appTheme.value) {
                AppTheme.SYSTEM_THEME -> setDefaultNightMode(MODE_NIGHT_FOLLOW_SYSTEM)
                AppTheme.NIGHT_THEME  -> setDefaultNightMode(MODE_NIGHT_YES)
                AppTheme.LIGHT_THEME  -> setDefaultNightMode(MODE_NIGHT_NO)
            }
        }
    

    UPD:

    第2点最好在Application.onCreate()中调用,以免在onCreate()中重新加载Activity

    【讨论】:

      【解决方案2】:

      您可以做的是使用Data Store 并将该切换的值分配给它。然后在您的setContent {} 中,您可以将其检查为:

      val theme = userSettings.themeStream.collectAsState()
                  val useDarkColors = when (theme.value) {
                      AppTheme.MODE_AUTO -> isSystemInDarkTheme()
                      AppTheme.MODE_DAY -> false
                      AppTheme.MODE_NIGHT -> true
                  }
      

      用户设置在哪里:

      enum class AppTheme {
          MODE_DAY,
          MODE_NIGHT,
          MODE_AUTO;
      
          companion object {
              fun fromOrdinal(ordinal: Int) = values()[ordinal]
          }
      }
      
      interface UserSettings {
          val themeStream: StateFlow<AppTheme>
          var theme: AppTheme
      }
      
      class UserSettingsImpl @Inject constructor(
          @ApplicationContext context: Context
      ) : UserSettings {
      
          override val themeStream: MutableStateFlow<AppTheme>
          override var theme: AppTheme by AppThemePreferenceDelegate("app_theme", AppTheme.MODE_AUTO)
      
          private val preferences: SharedPreferences =
              context.getSharedPreferences("sample_theme", Context.MODE_PRIVATE)
      
          init {
              themeStream = MutableStateFlow(theme)
          }
      
          inner class AppThemePreferenceDelegate(
              private val name: String,
              private val default: AppTheme,
          ) : ReadWriteProperty<Any?, AppTheme> {
      
              override fun getValue(thisRef: Any?, property: KProperty<*>): AppTheme =
                  AppTheme.fromOrdinal(preferences.getInt(name, default.ordinal))
      
              override fun setValue(thisRef: Any?, property: KProperty<*>, value: AppTheme) {
                  themeStream.value = value
                  preferences.edit {
                      putInt(name, value.ordinal)
                  }
              }
          }
      }
      

      那么它应该使用存储在Data Store中的那个而不是使用系统那个。

      这是来自Stefano Sansone的完整示例Compose theme switcher

      您也可以阅读Jetpack Compose Theming

      【讨论】:

      • 如果我理解正确,那么这就是应用程序记住用户选择的主题并将选择存储在“缓存”中这一事实的答案。我已经实现了这个,但我的问题是应用程序在低级别使用操作系统主题来使用相应的资源。例如,原来操作系统上的标准主题是白天,用户在我的应用程序的设置中选择了夜间主题,但应用程序仍然使用文件夹中的资源(即图像)作为白天主题
      猜你喜欢
      • 1970-01-01
      • 2018-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多