Android Q深色模式及源码解析

recreate(); // 这个是刷新,不然不起作用

有四个模式可以选

MODE_NIGHT_NO // 日间模式,使用light theme

MODE_NIGHT_YES // 夜间模式,使用dark theme

MODE_NIGHT_AUTO // 根据系统时间自动切换

MODE_NIGHT_FOLLOW_SYSTEM // 跟随系统设置,这个是默认的

3.2、通过 forceDarkAllowed 启用

如果嫌上面的方案麻烦,麻烦也有更简单的方案,那就是forceDarkAllowed强制转换,但是效果可能就没有自己适配那么完美了。

首先,可以通过在主题中添加 android:forceDarkAllowed="true"标记,这样系统在夜间模式时,会强制改变应用颜色,自动进行适配。不过如果你的应用本身使用的就是 DayNight 或 Dark ThemeforceDarkAllowed 是不会生效的。

另外,如果你不希望某个 view 被强制夜间模式处理,则可以给 view 添加 android:forceDarkAllowed="false" 或者 view.setForceDarkAllowed(false),设置之后,即使打开了夜间模式且主题添加了 forceDarkAllowed,该 view 也不会变深色。比较重要的一点是,这个接口只能关闭夜间模式,不能开启夜间模式,也就是说,如果主题中没有显示声明 forceDarkAllowedview.setForceDarkAllowed(true)是没办法让 view 单独变深色的。如果 view 关闭了夜间模式,那么它的子 view 也会强制关闭夜间模式

总结如下:

  • 主题若添加 forceDarkAllowed=false,无论 view 是否开启 forceDarkAllowed 都不会打开夜间模式

  • 主题若添加 forceDarkAllowed=true,view 可以通过 forceDarkAllowed 关闭夜间模式,一旦关闭,子 view 的夜间模式也会被关闭

  • 如果父 view 或主题设置了 forceDarkAllowed=false,子 view 无法通过 forceDarkAllowed=true 单独打开夜间模式为

  • 若使用的是 DayNight 或 Dark Theme 主题,则所有 forceDarkAllowed 都不生效

四、实现原理

上面我们说的 android:forceDarkAllowed 其实是分为两个用处,它们分别的定义如下:

Activity Theme级别:

//frameworks/base/core/res/res/values/attrs.xml

View级别:

//frameworks/base/core/res/res/values/attrs.xml

4.1、Theme级别

熟悉View树的构造原理的同学应该都知道,ViewRootImpl是View中的最高层级,属于所有View的根,所以该级别,我们需要在ViewRootImpl中查找原因,寻寻觅觅,最终在updateForceDarkMode函数中找到关于forceDarkAllowed属性的踪影

//frameworks/base/core/java/android/view/ViewRootImpl.java

private void updateForceDarkMode() {

//渲染线程为空,直接返回

if (mAttachInfo.mThreadedRenderer == null) return;

//判断当前uimode是否开启深色模式

boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;

if (useAutoDark) {

//读取开发者选项中强制smart dark的值

boolean forceDarkAllowedDefault =

SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false);

TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);

//读取Theme是浅色主题或深色主题,并且配置了forceDarkAllowed=true,

useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)

&& a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);

a.recycle();

}

//是否强制使用深色模式

if (mAttachInfo.mThreadedRenderer.setForceDark(useAutoDark)) {

// TODO: Don’t require regenerating all display lists to apply this setting

invalidateWorld(mView);

}

}

updateForceDarkMode 调用的时机分别是在 ViewRootImpl#setView 和 ViewRootImpl#updateConfiguration,也就是DecorView初始化和uimode切换的时候调用,确保在设置中切换深色模式时,能通知ViewRootImpl进行界面刷新。

我们继续跟踪 下HardwareRenderer#setForceDark 函数

//frameworks/base/graphics/java/android/graphics/HardwareRenderer.java

public boolean setForceDark(boolean enable) {

//当forceDark值发生变化才会进入下面逻辑,否则返回false,无需刷新界面

if (mForceDark != enable) {

mForceDark = enable;

nSetForceDark(mNativeProxy, enable);

return true;

}

return false

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值