夜间模式实践

作者: 李科吐温 | 来源:发表于2016-07-23 13:03 被阅读916次

现状

夜间模式是android换肤的一种,关于换肤的相关知识总结,大家可以参考这篇文章Android换肤技术总结-markzhai

夜间模式现状

夜间模式与换肤的不同:

  1. 夜间模式可以说是大部分应用发展到一定阶段都要实现的功能,而换肤功的需求广度不如夜间模式。
  2. 实现难度上来讲,换肤的实现会比夜间模式更复杂些,但是实现方式思路也已经比较成熟。
  3. 换肤的实现一般都是需要从apk外部加载皮肤资源,毕竟皮肤的种类比较多,都放到apk中不现实。而夜间模式则直接放到apk中就可以。

为什么要重新实现一个夜间模式库:

由于工程需要在原有基础上修改,就希望能有一个侵入性尽量小,以不影响现有工程的库,来实现夜间模式。考察了一些现有的夜间模式或换肤库,感觉工程需要修改的内容太多,所以决定做一个这样的库。

夜间模式要解决两个问题:

  1. 切换夜间模式后,新打开页面要以新的样式展示。
  2. 切换夜间模式时,已打开页面的刷新。

新页面的样式展示的解决方式:

新页面以新的样式的展示是一个比较容易解决的问题,替换resource这种类似的黑科技排出在外,我这里有两种实现思路,解决方式不同,其解决上面提到的问题2(刷新页面)的实现方式也相应的需要改变。

  1. 使用attr引用的方式实现两套主题,在Activity的onCreate方法中,在super.onCreate之前setTheme, Activity就可以以设置的Theme的样式展示。
  2. 使用官方在support appcompat 23.2.1中加入的夜间模式,使用AppCompatDelegate.setDefaultNightMode(int mode) 来全局启用需要的夜间模式,之后再打开新Activity将以新的方式展示。

刷新已打开页面的解决方式:

针对attr方式实现两套主题的方式,刷新已打开界面的的解决方式,我这里由于没有实践过,就不敢枉自猜测解决方式了。下面我们着重介绍以官方夜间模式为基础的刷新已打开页面样式的实现思路。

官方提供了夜间模式的支持,但是对于已经打开的页面还是需要重启来刷新样式。然而这种方式用户体验并不好。这样我们还是要解决不重启页面刷新页面的问题。那么有没有办法不重启就重新加载样式呢,答案是:没有,没有这样一个全局性的东西(至少我还没发现,如果有麻烦告诉我下)。我们只能针对性的对我们的View主动修改background,textColor等来使我们的页面达到刷新的效果。

这里呢我们又有两个问题需要解决:

  1. 哪些view需要刷新。
  2. 刷新哪些属性。
  3. 新样式从哪儿来。

对于问题1、2的解决我这里参考来张鸿洋老师的博客开源库。思路就是,代理我们Activity中View的创建过程,以通过他们在XML中设置的属性来判断是否我们需要刷新的View。如果是就将View和属性(比如android:background="@color/gray")cache起来,备用。

对于问题3(新样式从哪儿来)的解决,我们这里利用来官方提供的夜间模式的来解决。在使用官方提供的AppCompatDelegate.setDefaultNightMode(int mode) 方法之后虽然不能刷新已打开页面,但是我们同时再调用activity.getDelegate().applyDayNight()方法就之后,其实Activity中的Resource资源已久发生了改变。这个我们可以通过源码了解到,applyDayNight()方法最终调用了这样一段函数:

这个时候Resource会刷新自己已经缓存的资源内容。这个时候我们为Activity中的空间setBackgroundDrawable(mResource.getDrawable(int resId))已经是新的了(这个时候虽然资源id没变,但是它们指向的内容以及发生了变化)。

我们就这样解决了刷新问题。思路就是这样的。

遇到的问题:

在实践上面的方法中,也遇到了一些问题:

  1. ListView中为item设置了selector资源,刷新没有效果。这个通过反射设置Activityresource置空,让Activity重新生产resource来解决。
  2. Activitynew TextView(this)创建的view不能刷新,需要通过LayoutInflater.from(MainActivity.this).inflate(R.layout.item_layout, linearLayout, false);这种加载布局的方式来创建才能被刷新,因为我们需要让控件的创建走代理来已cache到新创建的控件。

我实现的轮子:

我通过上面的思路实现了一个库,尽量的降低了侵入性。要参考代码的可以走这里

相关文章

  • 夜间模式实践

    现状 夜间模式是android换肤的一种,关于换肤的相关知识总结,大家可以参考这篇文章Android换肤技术总结-...

  • Android夜间模式实践

    前言 由于项目需要,近段时间开发的夜间模式功能。主流的方案如下:1、通过切换theme实现2、通过resource...

  • 想用AppCompat的夜间模式切换功能又不想导整个库?

    目录 背景 Android中的夜间模式 AppCompat实现夜间模式 AppCompat夜间模式切换功能的分析 ...

  • 盘点win10系统里的六个神奇模式,总有一个你不知道!

    夜间模式 Win10系统加入了夜间模式,夜间模式自带护眼功能,让夜晚操作电脑的用户可以保护视力。 简单说夜间模式就...

  • Android实现夜间模式的方法(二)

    该文章接上篇 Android实现夜间模式的方法(一) 三.夜间模式的实现方案——单纯夜间模式 1.通过切换主题...

  • 微博iOS的护眼模式

    夜间模式的探讨 与其他App切换夜间模式不同: 微博采取了护眼模式: 两种方案各有利弊: 夜间模式优点:可以对每一...

  • 夜间模式

    又是一个夜晚 夜晚总会让人产生思考 这个夏天 这个暑假 找了一份暑假工兼职 算是体验生活 “享受”一下赚钱的不易 ...

  • 夜间模式

    思路: 一: 1.准备两套资源,分别对应日间模式和夜间模式。 2.在系统全局保存一个变量(BOOL isNight...

  • 夜间模式

    标签(空格分隔): Android 1、通过切换theme来实现夜间模式。2、通过资源id映射的方式来实现夜间模式...

  • 夜间模式

    夜间模式

网友评论

  • 任青春的风缠绵:这个库在support 24.x.x 版本中如果你为布局设置的background是selector的话夜间模式会失灵,我有时间的话就会处理它。
    请问这个库,这个问题解决了吗?
  • MycroftWong:不知道作者看吗,库写得很好,应该说非常好的那种。就是有个需求,在显示切换的时候不要那么僵硬,在这片文章中(http://www.jianshu.com/p/3b55e84742e5)他的实现方式就是你说的另一种思路。想说的是,他切换主题的时候 保存DecorView上的图像,添加一个将该图像alpha从1f到0f的动画,这样就感觉是渐变效果,而我这样来弄,却没有能够实现,不知道是什么原因,如果可以的话麻烦看一下,说一下原理。
    MycroftWong:@李科吐温 我后来看了下源码,需要在activity声明中添加configChanges=uiMode 这样可以避免acitivity重建。Toolbar以下部分是可以切换的,colorPrimary ...之类没起作用。
    如果能解决这个问题,再添加切换动画的话就完美了。比另外一种方式的解决方案好的一点就是侵入性几乎没有。
    李科吐温:@MycroftWong 因为24.x.x修改了夜间模式的一些方法,我还没有时间处理,所以这个库在support包23.2.1上的表现比24.x.x上要好。在24.x.x版本上,官方会自动重启activity
    MycroftWong:@MycroftWong 测试好了,Activity还是重建了:persevere:
  • Zach_C:还是不懂具体怎么实现
    李科吐温:@anhao_chan 其实主要思路就是,对于已经打开的页面,在页面创建时,找到所有需要刷新的控件,然后在切换主题时,主动刷新这些控件。最下面有Github地址,也可以参考下代码理解。代码不多就几个类

本文标题:夜间模式实践

本文链接:https://www.haomeiwen.com/subject/hlhwjttx.html