深色主题在 Android 9 及更早些时候,开发者需要通过 AppCompat 库的 DayNight 主题或自定义方案实现应用内深色模式,缺乏系统级联动。从 Android 10(API 级别 29)开始,官方提供了系统级的深色主题支持,并在 Android 11、12 中持续优化。以下是官方对深色主题支持的演进:
版本 | 时间 | 描述 |
---|---|---|
Android 10 | 2019 | 引入全局深色主题,用户可在系统设置中一键切换,系统界面和应用(适配后)会跟随主题变化。 |
Android 11 | 2020 | 优化了深色主题的调度(如定时切换),并增强了对第三方应用图标和控件的适配。 |
Android 12 | 2021 | 引入 Material You 设计语言,支持更灵活的主题自定义(如动态取色),进一步统一深色体验。 |
1、实现深色主题
参考官方的技术文档《实现深色主题》即可完成功能的实现。大致步骤为:声明主题继承关系、创建夜间模式资源目录、使用 AppCompatDelegate
切换主题。这种模板化的代码实现并不是这里要讨论的话题。假设我们已经实现了深色主题功能,并在应用的 Application
类对主题进行了监听和初始化,代码如下:
1 | class NoteApplication : Application() { |
在 Application
中初始化主题,启动页面也可以在第一时间响应主题的初始化。但由于 AppCompat
的行为变更, 会导致启动页被创建 2 次,从而会启动 2 次主页面,这在体验上给用户造成了很大的困惑。
✦ 注意:从 AppCompat V1.1.0 开始,setDefaultNightMode() 会自动重新创建任何已启动的 activity。
好在官方提供了用户可自行处理深色主题的实现。因为,当应用的主题发生更改时,都会触发 uiMode
配置变更。这意味着系统会自动重新创建 Activity
。这时,我们希望接管这种配置变更后的行为,以便按照自己的意愿做出响应。通过声明 Activity
可以处理 uiMode
配置变更,自行处理深色主题的实现:
1 | <activity |
当 Activity
声明它会处理配置变更时,系统会在出现主题变更时调用其 onConfigurationChanged()
方法。
1 | class StarterActivity : BaseActivity<ActivityStarterBinding>() { |
通过这样的操作,即可完成启动页对主题的响应,并且合理的避开了页面的重建造成下游页面的多次启动。
2、新的实现方式
上述的实现方式可以解决启动页的主题响应,如果 API 级别为 31及更高,可使用新的方式进行实现。参考如下:
对于 API 级别 31 及更高级别,请使用
UiModeManager#setApplicationNightMode
告知系统您的应用运行的是哪个主题。这样,系统就可以 在启动画面期间显示主题。在 API 级别 30 及更低级别中,请使用
AppCompatDelegate.setDefaultNightMode()
来切换主题。
使用 UiModeManager
不仅可以实现启动页对主题的响应,同时也不用为 Activity
声明 uiMode
响应配置变更来规避页面重复创建的问题。
1 | class NoteApplication : Application() { |