android自动夜间模式吗,Android夜间模式的实现方案

原标题:Android夜间模式的实现方案

作者简介

本篇来自 Sunlight1024的投稿,详细地讲解了关于Android应用的夜间模式的实现,希望大家喜欢!

Sunlight1024的博客地址:

http://blog.csdn.net/qq_20521573

前言

对于一款阅读类的软件,夜间模式是不可缺少的。最初看到这个需求时候觉得无从下手,没有一点头绪。后来通过查阅资料发现 Android 官方在 Support Library 23.2.0 中已经加入了夜间主题。也就是只需要通过更换主题便可实现日间模式和夜间模式的切换。

下面截取项目实现的夜间模式效果图:

03be1d9d1e6fd08df325dad880d3347b.gif

效果看起来还比较 nice,没有闪屏,过度也比较平滑。那么项目中的这个日间、夜间模式切换效果是如何实现的呢?下面将从以下几个方面来讲解:

实现夜间模式需要的配置

实现白天和夜间模式的切换

实现遇到的问题及解决方案

实现夜间模式需要的配置

首先在 gradle 中引入以下依赖

让我们项目的主题继承夜间模式主题,在 style 中设置如下主题:

d8872542961593564ba499b2f36b268f.png

新建 drawable-night 和 values-night 的资源目录。如果要适配不同分辨率的屏幕则可新建 drawable-night-hdip、drawable-night-xhdpi 等目录来存放不同分辨率的图片资源。values-night 目录下存放与夜间模式相关的 value 文件。本篇文章讲解仅以夜间模式和日间模式的颜色为例,在 values-night 目录下新建 color.xml 文件。

新建 values-night 目录,如下:

4561338fe14e0ffec79a48e407aa33b6.png

39d9e146e0fbee0fbea7c975b6cb11a5.png

在 values-night 目录下新建 colors 文件,如下:

30970331fdfbcc35c51e74df31891a2d.png

a9cc57978c74f371a7758cf8eb57f1e8.png

接下来只需要在对应的 colors 文件下写不同的颜色值(夜间颜色值和白天颜色值)即可。至此关于实现夜间模式的配置已经基本完成。

实现白天和夜间模式的切换

启动 App 时检测是否处于夜间模式

如果是则切换至夜间主题。这个需要在自己项目的 Application 中实现。可在自己项目的 Application 中添加以下代码:

8881d9233e2176c9cb51ce0eb8b413e8.png

这里需要介绍一下有关夜间模式的几个常量值

AppCompatDelegate.setDefaultNightMode(mode), 其中 mode 有一下四个值:

MODE_NIGHT_NO: 亮色(light)主题,不使用夜间模式

MODE_NIGHT_YES:暗色(dark)主题,使用夜间模式

MODE_NIGHT_AUTO:根据当前时间自动切换 亮色( light )/暗色( dark )主题(22:00-07:00时间段内自动切换为夜间模式)

MODE_NIGHT_FOLLOW_SYSTEM(默认选项):设置为跟随系统,通常为MODE_NIGHT_NO

接下来需要我们在设置页面点击 ToggleButton 时切换白天/夜间模式

具体实现如下:

71737c3930a0be91fb151fa0f2bd3f8a.png

注意,上面代码中设置白天/夜间模式的代码的最后调用了 recreate() 方法重启了当前 Activity。但这样写切换模式时会有闪屏问题,体验比较差。具体优化将在下一节中实现。

实现遇到的问题及解决方案

利用谷歌官方提供的这个方案实现夜间模式的过程中遇到了不少的问题。且网上资料较少,大多文章讲解仅仅以一个简单的 demo 为例。但在用到实际项目中时会遇到很多的麻烦。这里主要总结了笔者曾经遇到过的难以解决的几个问题。

白天/夜间模式切换时闪屏问题

上一节中已经提到了在调用 recreate() 方法时会有闪屏问题。其实闪屏问题的解决比较简单。我们大可以不掉用 recreate() 方法,而是自己重启当前 activity 并为 activity 设置启动和退出动画即可!实现代码如下:

2dbe4ac34829b79e426ccf554736763a.png

如上代码,我们自行调用 startActivity 启动了设置页面并为其添加了一个透明渐变的启动动画。最后调用finish结束掉旧的设置页面。这样闪屏问题便迎刃而解。模式切换也变得流畅自然。

切换夜间模式后返回 MainActivity,MainActivity 页面没有更新

解决这个问题可以在切换模式后从设置页面发送一个广播,然后在 MainActivity 中接收到这个广播后重启 MainActivity 即可。根据官方的推荐更换夜间模式后需要调用 recreate() 方法刷新页面。但是 recreate() 方法巨坑无比,调用 recreate() 方法引起了诸多问题。详见问题3、4、5。因此解决这个问题笔者并没有在 MainActivity 调用中调用 recreate() 方法。而是在 SettingActivity 中定义了一个 boolean 值来标记是否切换了夜间模式。然后重写了 onKeyDown() 方法。如果切换了夜间模式则在返回时发出一个广播结束掉 MainActivity ,然后调用 startActivity() 重启了 MainActivity 并添加了启动动画,让用户感觉是只是返回了主页面。其实思想跟解决问题1有些类似。还是结合代码来看吧。

SettingActivity 中的代码

739d8b91f8fcf9c0ad75eefd01ec8a9b.png

MainActivity 中的代码:

212e174fcee43e32a9673e4dc300bbd0.png

最后还有点问题需要说明,由问题1我们可以知道,改变模式后,我们重启了 SettingActivity。因此在该类中定义的一个标记是否切换了夜间模式的 boolean 值并不能起到作用。解决办法是将这个值保存到SharedPreference中。然后重启 SettingActivity 后再取出该值。可以看代码,这点真心有点绕啊。。。

注意问题1中的 setNightMode() 方法中有一句代码

UserInfoTools.setChangeNightMode(this,true);

将改变了夜间模式设置为了 true 并保存到了 SharedPreferences 中,然后在onCreate()中有以下代码来初始化 isChangeNightMode 的值。

19aeefbdee481fa95e0042671c097a5b.png

设置白天/夜间模式后出现无故闪退问题

这个问题说来比较奇怪,原因是切换了夜间模式后在 MainActivity 中调用了 recreate() 方法。具体原因笔者也没有弄清楚,调试了好一阵子也没有找出个所以然来。后来果断放弃了在 MainActivity 中调用 recreate() 方法,而是换成了 startActivity() 重新启动了 MainActivity。之后这个问题便不复存在了。

点击 ToggleButton 切换模式后应用黑屏,随后挂掉

这个问题的最终原因还是因为 recreate() 方法引起的。如果你用了 ToggleButton 切换白天/夜间模式,并且为 ToggleButton 设置了 setOnCheckChangedListener() 方法,那么你将有很大概率碰到这个问题。引起这个问题的原因是因为调用了 recreate() 方法后 Activity 重新启动,但是新启动的 Activity 保存了之前 Activity 的状态。因此在重启时候重新设置了 TouggleButton,继而调用了又 setOnCheckChangedListener() 方法,结果悲剧了。。。一个死循环产生了,程序不黑屏才怪。因此最简单的办法是放弃 recreate() 方法,改用问题1中的方法!(其实细心的小伙伴应该已经发现了,我的代码中仅仅是为 ToggleButton 设置了 setOnClickListener() ….机智如我啊)如果你有强迫症必须要使用 setOnCheckChangedListener 和 recreate() 方法那么也不是没有解决方案。可以定义一个 boolean 成员变量,然后在 onCreate() 方法中判断 savedInstanceState 是否为 null,然后给这个 boolean 成员变量赋值,并在 setOnCheckChangedListener() 方法中根据这个 boolean 成员变量的值去调用设置夜间模式的方法即可。

设置夜间模式后 MainActivity 调用 recreate() 方法,MainActivity 中的”发现“页面没有加载出来

发现页面如下面图片所示,也就是一个 Fragment 中嵌套了一个 ViewPager。调用recreate() 后整个 ViewPager 消失了。。。没有加载出来!!!

f22358301988d172cd92d7a65180b3a3.png

解决方案,放弃使用 recreate(),改用问题1中的方法!

万恶的 recreate() 方法!难道是我使用的姿势不对?返回搜狐,查看更多

责任编辑:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值