如何让单个Fragment仅用深色主题,其余应用为DayNight模式?
```
DayNight的本质是在不同资源目录下继承不同父主题:
<!-- values 目录中 --> <style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat.Light" /> <!-- values-night 目录中 --> <style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat" />
我尝试创建一个不继承自DayNight的独立深色主题,期望它能使用values-night文件夹中的颜色:
<style name="AppTheme.Dark" parent="Theme.MaterialComponents.NoActionBar"> <item name="android:windowBackground">@color/surfacePrimary</item> <item name="colorPrimary">@color/surfacePrimary</item> <item name="colorPrimaryDark">@color/surfacePrimary</item> ... </style>
两个主题的颜色属性指向相同的资源,但这些颜色在values/colors.xml和values-night/colors.xml中值不同。随后我在目标Fragment的onCreateView中应用该深色主题:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { activity?.theme?.applyStyle(R.style.AppTheme_Dark, true) return inflater.inflate(R.layout.fragment_b, container, false) }
但这种方法并未生效。我希望避免为该Fragment添加独立颜色值,而是复用已有的深色模式颜色资源,请问如何强制AppTheme.Dark使用values-night/colors.xml中的颜色?
解决方案
方法1:使用AppCompat本地夜间模式设置(推荐)
如果你基于AppCompat库开发,直接通过AppCompatDelegate强制Fragment使用夜间模式,自动加载values-night下的所有资源:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 强制当前Fragment使用夜间模式资源 AppCompatDelegate.setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_b, container, false) } override fun onDestroy() { super.onDestroy() // 恢复系统默认夜间模式,避免影响其他页面 AppCompatDelegate.setLocalNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) }
这种方式无需修改主题结构,直接复用已有深色资源,且不会污染其他页面的主题设置。
方法2:创建强制深色配置的Context
通过构建带有夜间模式配置的Context,让Fragment布局加载时优先读取values-night资源:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { context?.let { originalContext -> // 构建夜间模式配置 val darkConfig = originalContext.resources.configuration.apply { uiMode = uiMode and Configuration.UI_MODE_NIGHT_MASK.inv() or Configuration.UI_MODE_NIGHT_YES } // 创建深色配置的Context val darkContext = originalContext.createConfigurationContext(darkConfig) // 应用深色主题 darkContext.theme.applyStyle(R.style.AppTheme_Dark, true) // 使用新Context加载布局 val darkInflater = darkContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater return darkInflater.inflate(R.layout.fragment_b, container, false) } return inflater.inflate(R.layout.fragment_b, container, false) }
方法3:为深色主题绑定固定深色资源
在values目录下创建深色颜色别名,直接指向values-night中的颜色值:
- 在
values目录新增colors_dark_refs.xml:
<resources> <!-- 别名直接引用values-night中的颜色 --> <color name="surfacePrimary_dark">@color/surfacePrimary</color> </resources>
- 修改深色主题使用别名:
<style name="AppTheme.Dark" parent="Theme.MaterialComponents.NoActionBar"> <item name="android:windowBackground">@color/surfacePrimary_dark</item> <item name="colorPrimary">@color/surfacePrimary_dark</item> <item name="colorPrimaryDark">@color/surfacePrimary_dark</item> ... </style>
这种方式通过资源别名复用已有深色颜色,无需重复定义颜色值。
内容的提问来源于Stack Exchange,提问作者Marat
相关产品推荐
相关产品推荐

