小米手机深色模式适配说明

Android 10 (API 级别 29) 及更高版本中提供深色主题背景。深色主题背景具有诸多优势:

小米手机深色模式适配说明

1.深色模式背景与介绍

1.1.安卓原生深色模式介绍

Android 10 (API 级别 29) 及更高版本中提供深色主题背景。深色主题背景具有诸多优势:

  • 可大幅减少耗电量(具体取决于设备的屏幕技术)。
  • 为弱视以及对强光敏感的用户提高可视性。
  • 让所有人都可以在光线较暗的环境中更轻松地使用设备。

深色主题背景同时适用于 Android 系统界面和在设备上运行的应用。在 Android 10 (API 级别 29) 及更高版本中,您可以通过以下三种方法启用深色主题背景:

  • 使用系统设置(Settings -> Display -> Theme)启用深色主题背景。
  • 使用“快捷设置”图块,从通知托盘中切换主题背景(启用后)。
  • 在 Pixel 设备上,选择“省电模式”将同时启用深色主题背景。其他原始设备制造商 (OEM) 不一定支持这种行为。

可参考:https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#top_of_page

1.2.MIUI深色模式介绍

深色模式是一种将屏幕主色调转为深色的模式。如下图MIUI10界面为例,上图是正常浅色背景,下图为MIUI深色模式。

小米手机深色模式适配说明
小米手机深色模式适配说明

用户在MIUI中有两个方式可以打开深色模式:1.设置-显示-深色模式 2.下拉控制中心 中可以开启,开启后将全局变黑如上图显示:

小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明

对于适配深色模式的应用来说,我们会优先启用应用的深色模式。未接入的应用,则会通过算法进行反色。适配方式将在第三部分详细描述。如果用户不希望某个应用被反色,用户可以手动关闭该应用的反色功能,见下方:

小米手机深色模式适配说明
小米手机深色模式适配说明

目前已有众多知名头部三方应用适配了深色模式,例如微信、QQ、爱奇艺、优酷、知乎、小红书、钉钉等。

2.适配深色模式的好处

我们强烈建议您为您的应用适配深色模式,主要有如下原因:

  • 更酷、更时髦的流行趋势

作为一种全新的潮流,黑色界面受到众多用户、尤其是年轻用户的欢迎。目前,各大安卓系统、iOS系统都已经支持深色模式,众多主流头部应用也已适配或正在适配深色模式。                

  • 让用户更专注于内容

深色背景下,文字、图片、视频都能更清晰地呈现,尤其是暗光环境下。对于浏览器、资讯和视频类app,深色可以让用户沉浸其中,为应用贡献更多的使用时长:对于使用时段是晚上的应用,这一特性更加明显。                                               

  •  降低应用的耗电量                                               

省电是用户最关注的性能之一。低电情况下,用户更青睐使用深色模式的应用。根据小米实验室测试数据:

OLED屏幕100%亮度下,深色模式耗电相比浅色模式,最高降低83%;

OLED屏幕50%亮度下,深色模式耗电相比浅色模式,最高降低50%。

  • 推广优待适配深色模式时可以联系我们,小米可以为应用提供应用商店专题和微博宣传等方式,为应用增加额外的宣传。
小米手机深色模式适配说明

3.适配方式

适配方式有两种:

  • 适配深色模式资源:开发者根据自身应用设计深色模式,按照适配规范进行适配。
  • 适配全局反色:利用安卓Q上提供的forcedark能力可以直接反色。

在适配前,开发者需要考虑是否在自有应用内增加深色模式开关。我们建议的方式:

  • 务必提供跟随系统深色模式的选项。可以默认跟随系统,或在监测到系统切换为深色/浅色时提示用户。 
  • 可以为用户提供手动切换的开关。

目前已有三方应用如下(左 小红书 右 QQ),仅供参考:

小米手机深色模式适配说明
小米手机深色模式适配说明

方式一 适配深色模式资源                                           

适配深色模式资源需要设计师先对所有页面设计深色页面,再由开发完成深色模式资源开发。

优点:在所有安卓版本、所有手机厂商用户均可以使用,且体验较好。

3.1.谷歌适配要求

开发者可基于谷歌深色模式适配标准进行适配:https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#top_of_page

已经适配过的页面要将ForceDarkAllowed()​参数值设置为false,若整个主题均已适配深色模式,则需要将这个主题的ForceDarkAllowed()参数值设置为false。

3.2.小米深色模式配色标准设计

小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明
小米手机深色模式适配说明

其余适配建议详见设计文档:附件1-小米深色模式配色标准设计文档。

3.3.接入方式

3.3.1.接入介绍

  • 根据谷歌深色模式接入标准,如要支持深色主题背景,您必须将应用的主题背景(通常可在res/values/styles.xml中找到)设置为继承 ​DayNight​ 主题背景:
<style name="AppTheme" parent="Theme.AppCompat.DayNight">

您还可以使用 MaterialComponent 的深色主题背景

<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">

这会将应用的主要主题背景与系统控制的夜间模式标记相关联,并将应用的默认主题背景设置为深色主题背景(如果已启用)。详细内容见:https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#force_dark

从开发的角度说,就是打开夜间模式后,系统会优先从xxx-night资源中寻找资源并替换。
Android系统从2.2开始就已经⽀支持了了DarkMode,其对应接口是名为“uimode”的系统服务,DarkMode所使⽤用到的接口方法是:setNightMode、getNightMode分别对应设置夜间模式和获取设置状态。

// 获取uimode系统服务
UiModeManager uiModeManager = (UiModeManager)
getSystemService(Context.UI_MODE_SERVICE);                                             
// 获取设置状态
int currentMode = uiModeManager.getNightMode();                                               
// 设置夜间状态
uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_AUTO); // ⾃动
uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES); // 启⽤
uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); // 停⽤
                                             
在日志中的体现:
------------------------------------------------------                                                        
DUMP OF SERVICE uimode:
Current UI Mode Service state:                                                        
mDockState=0 mLastBroadcastState=0                                                        
mNightMode=2 mNightModeLocked=false
mCarModeEnabled=false mComputedNightMode=false
mCarModeEnableFlags=0 mEnableCarDockLaunch=true                                                        
mCurUiMode=0x2d mUiModeLocked=false mSetUiMode=0x2d
mHoldingConfiguration=false mSystemReady=true
mTwilightService.getLastTwilightState()=null                                                        
--------- 0.001s was the duration of dumpsys uimode,ending at: 2019-01-18 00:00:01--------------

从uimode服务dump出来的信息可以判断:

mNightMode的取值:0 → AUTO; 1 → NO; 2 → YES另外,在Android O开始,Android⽀支持adb命令启动和停⽤用DarkMode,具体命令是:adb shell cmd uimode night <auto | yes | no>

O以前的机型,只能通过代码调用uimode接口启动和停用DarkMode。需要注意的是,miui虽然从level 16开始支持DarkMode,但是并不意味着miui之前的版本不能切换DarkMode,用户完全可以通过命令或者代码调用系统接口,启动和关闭DarkMode。而Setting中的开关是阻⽌不了的,除⾮MIUI对这个权限进行收紧。   

MIUI SDK从level 16开始,支持DarkMode,所以的支持DarkMode,是指MiuiSDK增加了新的主题,DayNight,来自适应的适配Light和Dark主题。其实在16之前的SDK上,Light和Dark主题都是一直存在的,只是没有一个自动适配的机制存在,而且Dark主题存在一些Bug,并不是它应该是的样⼦。适配过程中,存在一些APP,之前就是在Dark主题下进行的开发,那么在sdk level 16以后,发现Dark模式存一些问题,比如弹窗变成了⿊⾊,均是因为Dark主题修改造成的。附录中会给出SDK针对Dark和Light进行的改动,包括所有受影响的资源和主题样式修改。

3.3.2.接入方式详细说明                                              

重点说明⼀下接⼊和使⽤⽅式。这⾥除了Theme.Light.DarkActionBar这个主题以外,所有Light(Dark)主题均有对应的DayNight主题。

  • 对于非解耦应⽤,可以直接使⽤Miui SDK的public的资源和属性。

代码接⼊方式:可以直接将使⽤MiuiSdk的Light或者Dark主题的地方,替换成DayNight主题,⽐如:将

<style name="MiuiDemo.Theme.Test" parent="miui:Theme.Light">
或者<style name="MiuiDemo.Theme.Test" parent="miui:Theme.Dark"> 
替换成<style name="MiuiDemo.Theme.Test" parent="miui:Theme.DayNight">

Java代码中:将使⽤Light主题的所有地⽅miui.R.style.Theme_Light替换成miui.R.style.Theme_DayNight

  • (如果本身就是⾃升级应用,就不⽤看这⼀步了)对于解耦自升级应⽤,需要在gradle中进行如下操作:   
1)修改build.gradle中的dependencies,使⽤用miui插件,如下:(以gradle 3.3.0为例)
dependencies {                                               
classpath 'com.miui.tools.build:gradle:3.3.0'
}
2)gradle/wrapper/gradle-wrapper.properties⽂文件中的gradle修改到5.0,即:
distributionUrl=http://sdk.pt.miui.com/miuisdk/software/gradle/gradle-5.0-all.zip
3)此步,3.2.0可以忽略略,在3.3.0下必须将:                                                
apply plugin: 'com.android.application'
改成
apply plugin: 'com.miui.application'                                       
4)如果gradlew的⽇日志中有如下输出:
add property to gradle.properties of this project:                                                
android.aapt2FromMavenOverride=/home/{username}/.miuisdk/build-tools/aapt/28/aapt2
则修改gradle.properties,最后加一行:
android.aapt2FromMavenOverride=//home/{username}/.miuisdk/build-tools/aapt/28/aapt2
5)增加依赖:
compileOnly 'com.miui:core:alpha-SNAPSHOT'

于是,miui sdk中的Theme.DayNight就接入完成,在APP中可以直接使⽤Theme.DayNight.<…>主题。针对之前的miui:Theme.Light主题或者miui:Theme.Dark主题,均有对应的Dark或者Light主题。所以,如果需要适配自动切换夜间和日间模式,只要替换成对应的DayNight主题即可,DayNight主题负责⾃动切换两种(Dark和Light)主题。

  • (非单发应⽤请忽略)对于单发应用:单发应用的接⼊⽅式,可以参考:MIUI SDK support包的使用指南将依赖由:compileOnly ‘com.miui:core:alpha-SNAPSHOT’改成 implementation ‘com.miui.support:core-compat:alpha-SNAPSHOT’
  • 对于单发或者⾃升级应⽤,在代码接入上完全可以参考1中的代码接入方式。即,替换Light或者Dark为DayNight。但是,对于⾃自升级来说(单发应⽤不会有这个问题,因为单发应用已经将DayNight主题打包进APK),由于不确定⾃升级的目标ROM是否⽀持DayNight主题,所以如果在没有DayNight主题的ROM上⾃自升级,就会崩溃。这⾥需要看下⾯的注意事项1,可以找到解决方案。详见开发文档:附件2-深色模式开发文档

方式二 适配全局反色

全局反色利用安卓Q上提供的forcedark能力可以直接反色,对于开发者来说较为友好。

  • 优点:开发工作量小,适配较快。
  • 缺点:仅安卓Q手机可以使用该功能,复杂页面用forcedark适配难度较大;非原生的Webview无法反色,图片无法反色。

可以在安卓Q手机上,打开以下开关即可体验安卓Q反色能力,查看本应用反色后的情况。开关位置如下:

小米手机深色模式适配说明

3.4.谷歌Force Dark适配要求

Android 10 提供 Force Dark 功能。一如其名,此功能可让开发者快速实现深色主题背景,而无需明确设置 ​DayNight​ 主题背景。如果您的应用采用浅色主题背景,则 Force Dark 会分析应用的每个视图,并在相应视图在屏幕上显示之前,自动应用深色主题背景。有些开发者会混合使用 Force Dark 和本机实现,以缩短实现深色主题背景所需的时间。应用必须选择启用 Force Dark,方法是在其主题背景中设置 ​android:forceDarkAllowed=”true”​。此属性会在所有系统及 AndroidX 提供的浅色主题背景(例如 ​Theme.Material.Light​)上设置。使用 Force Dark 时,您应确保全面测试应用,并根据需要排除视图。如果您的应用使用深色主题背景(例如​Theme.Material​),则系统不会应用 Force Dark。同样,如果应用的主题背景继承自 DayNight​主题背景,则系统不会应用 Force Dark,因为会自动切换主题背景。

3.5.MIUI深⾊模式适配的目标和方法

在MIUI12上推出全局的深色模式,所有系统应用和主流三方应用适配。在MIUI12上用户开启深色模式后将默认开启全局反色。要达到的效果:系统切换到深⾊模式以后,应⽤也随之切换到深色模式,这是我们这次MIUI适配深色模式要达到的目标,也是我们对每个系统应⽤的要求。

适配的⽅法有三种:                                          

  • Android原生的深色主题
  • 全局反⾊
  • 第三方框架或者应用⾃自己实现深色模式  

目前只有Android Q深色模式支持全局反色:Android Q上提供了两种实现深色模式的⽅式:深色主题和全局反⾊。

深⾊主题即Theme.AppCompat.DayNight或者Theme.MaterialComponents.DayNight。深⾊主题是Android官⽅提供的实现深色模式的一种方法,应用也可以其它自己的方法实现深色模式。深⾊主题起作用后,将会加载-night⽬目录下的资源,如果没有找到,那么加载默认资源。对于标准控件,如果应用不提供深色模式的资源,系统也会提供一套默认的深色资源(不过比较难看,基本不可用)全局反色即ForceDark,系统会根据一套算法,计算出每个View属于前台还是后台。对于前台View,会使其变亮,对于后台View,会使其变暗,⽽不需要开发者提供两套资源。具体的原理可以移步Android Q Force Dark调研。如果一个activity使⽤了深色模式,那么全局反色对其将不生效。    

3.6.接入方式介绍

3.6.1.建议的整体适配步骤                                              

  • 现状评估

打开系统的深⾊模式,看看⾃⼰应用中那些⻚面有没有问题,一般可以分为三类:

A.适配了深色模式没有问题

B.没有适配深色模式的

C.适配了深⾊模式但是有问题的

  • 全局反色过滤

对于所有的A,请务必禁用全局反色,否则全局反色可能会和已有的深⾊模式效果冲突。对于所有的B,可以设置 <item name=”android:forceDarkAllowed”>true</item> ,然后可以打开全局反色,观察有没有问题。没有问题的,那就适配完成了,问题⽐较⼤的归为D。

  • 全局反色问题分析                                       

对于所有的D,分析问题的原因,是反色本身的问题还是⾃己应⽤导致的,⽐如布局存在有问题,有图片、webVIew等。其他的看下能不能通过调整布局等最后还是通过全局反⾊简单解决,剩下统一归为C。

  • 重新适配

对于C,看看是不是原来的适配方法有问题,有没有必要采用新的适配⽅法、框架,可不可以采用系统的深色主题等重新适配。                                              

  • 验证

打开系统深色模式,重新测试所有页⾯。

比较理想的做法是:建议采用深色主题和全局反色相结合的方式。整个应用用的主题使用DayNight,设置<item name=”android:forceDarkAllowed”>false</item>。对于已经⽀持深色主题或者用其他方法实现了深⾊模式的⻚面,没必要再支持全局反⾊,务必禁⽤。对于需要使用反⾊的⻚面,使⽤Light主题,设<itemname=”android:forceDarkAllowed”>true</item>。其他⻚面单独适配。                                             

3.6.2.深色主题的适配

深色主题在Android Q之前就是已经有了的,只不过其在Android Q上得到了了加强。一个activity如果想使用深色主题,让其主题继承于DayNight主题或者让整个应用的主题继承于DayNight主题即可。不过,上⾯的做法只适合跟随系统变化的需求,如果有高级的需求,⽐如应用想要主动切换到深⾊色主题或者不跟随系统变化,而是让⽤户选择,那么需要这样做:

1.监听UImode的变化。manifest中 activity 设置属性 android:configChanges=”uiMode”,并重写onConfigurationChanged。注意,声明了configChanges系统将不不会重建对应的activity,⽽而是回调onConfigurationChanged,需要activity⾃己处理变化的情况

2.让Activity继承于AppCompatActivity,这样子可以通过AppCompatDelegate.setDefaultNightMode(mode) 设置当前activity的mode,通过AppCompatDelegate.getDefaultNightMode()获取当前设置的mode。系统可以选择的mode有四种,具体解释可以看下面第1篇文章。

3.用户选择夜间模式的时候,保存用户选择的模式到SharedPreferences,调用recreate()重启activity,注意recreate()是重新创建activity,会回调所有生命周期方法。

4.activity启动的时候,取出之前保存的模式,通过AppCompatDelegate.setDefaultNightMode(mode) 进行当前activity的mode。                                            

5.系统UImode发⽣变化的时候,即onConfigurationChanged时,获取系统当前的UImode,根据应用⾃身的逻辑判断需不需要改变当前activity的mode,如果需要改变重复第3、4步。

切换到深⾊模式时,资源应用的顺序:                                  

  • 应用提供的-night资源
  • 应⽤设置的默认资源(通常是亮色下的资源,也可以是应用主动在深⾊模式下设置的主题)
  • 系统的默认深⾊资源
  • 系统默认的亮色资源

所以,凡是应用⾃己提供资源了的,那就提供两套,要么就全部⽤用系统的默认资源。如果一个应⽤没有使用DayNight主题,那么只会变化应用提供的-night深⾊资源,其他不会变化,系统也不会应⽤标准控件的默认深色资源。

具体实现,可以参考:  

https://segmentfault.com/a/1190000011472198
https://blog.csdn.net/xiaoxiaocaizi123/article/details/90370275

有两种方式,⼤同小异,相信大家能看得懂。

3.6.3.全局反色的适配      

⾸先来看下全局反色生效前提:

系统端:1.开启深色模式

应用端:1.activity对应的主题是Light的 2.对应的控件允许全局反色,默认是forceDarkAllowedDefault,这个值由系统属性debug.hwui.force_dark决定,debug.hwui.force_dark⼜是由全局反⾊的开关控制,默认是关闭的。         

以上几点缺⼀不可,需要详细说明几点是:

1.实现了深色主题的activity是不会受全局反色的影响,前面说了,深⾊主题是DayNight,不属于Light

2.如果一个控件没有申明forceDarkAllowed,那么forceDark是否⽣效取决于全局反色是否开启,如果全局反色开启,那么forceDark生效,否则不生效;

如果一个控件声明了forceDarkAllowed = false,那么无论如何都不会生效;

如果一个控件声明了forceDarkAllowed = true,那么只要开启深色模式,全局反色就会⽣效。             

3.forceDarkAllowed可以在主题xml中申明,也可以在代码中动态设置,动态设置可以具体到某⼀个view,后者会覆盖前者。遵循覆盖原则,即子View的声明会覆盖父View的声明,activity的会覆盖这个应⽤的申明。

适配全局反色的步骤:                                                

1.compileSdkVersion 设为29, 否则会编译失败,targetSdkVersion 貌似没有要求。

2.对于需要使用forceDark的activity,务必让其实现Light主题,Dark主题、DayNight主题都不会⽣效。

3.在activity的主题中申明<item name=”android:forceDarkAllowed”>true</item> 或者 在onCreate中,在setContentView之前,调⽤getWindow().getDecorView().setForceDarkAllowed(allowed)。

最后提供demo,需要的可以参考一下,源码:https://github.com/CQULittleMing/AndroidDemo/tree/master/demo

操作路径:  View – View 下面最后的两个。     

4.FAQ

4.1.全局反色的局限

  • 目前全局反色只是实验性功能,存在很多bug,不可过于依赖,更多可以参考Force Dark目前存在的问题。
  • 不会反色图⽚。
  • WebView/Flutter⽀持不完善所以如果一个⻚面存在Flutter书写、WebView或者亮色的图片,建议还是使⽤深色模式进行适配。

4.2.如何开启和禁用全局反色

设置是否⽀持全局反色有静态和动态两种方法:                                              

静态方式就是对应用或者activity的主题中声明<item name=”android:forceDarkAllowed”>true</item> 或者 <item name=”android:forceDarkAllowed”>false</item>;

动态⽅法是调用View.setForceDarkAllowed(true)或者View.setForceDarkAllowed(false),对DecorView设置可以对整个窗口起作⽤。

5.联系我们

有任何问题可以随时联系我们:

商务合作:liushuo3@xiaomi.com

产品问题:zhangyanan10@xiaomi.com

研发问题:darkmode@xiaomi.com

编辑:yimen,如若转载,请注明出处:https://www.yimenapp.com/kb-yimen/12151/

部分内容来自网络投稿,如有侵权联系立删

(0)
上一篇 2022年11月24日 上午11:19
下一篇 2022年11月24日 上午11:23

相关推荐