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

作者简介

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

Sunlight1024的博客地址:

http://blog.csdn.net/qq_20521573

前言

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

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

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

实现夜间模式需要的配置

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

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

实现夜间模式需要的配置

首先在 gradle 中引入以下依赖

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

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

新建 values-night 目录,如下:

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

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

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

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

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

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

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 时切换白天/夜间模式

具体实现如下:

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

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

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

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

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

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

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

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

SettingActivity 中的代码

MainActivity 中的代码:

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

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

UserInfoTools.setChangeNightMode(this,true);

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

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

这个问题说来比较奇怪,原因是切换了夜间模式后在 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 消失了。。。没有加载出来!!!

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

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

责任编辑:

android自动夜间模式吗,Android夜间模式的实现方案相关推荐

  1. android 自动挂断,[转]android 来电自动接听和自动挂断

    注意:android2.3版本不支持下面的自动接听方法.(会抛异常:java.lang.SecurityException: Neither user xxxxx nor current proces ...

  2. android 自动读取短息,Android实现短信验证码自动拦截读取功能

    本文实例为大家分享了Android短信验证码自动拦截读取 的具体代码,供大家参考,具体内容如下 知识准备: 1.观察者模式的理解[文章稍后来到~~] 2.Android的Cursor使用[Androi ...

  3. android 自动下一首,Android播播放完SD卡指定文件夹音乐之后,自动播放下一首

    最近做一个项目,需要连续播放音乐,播放完一首歌之后,自动播放完下一首歌.不要重复播放. 代码如下: package com.example.asyncplayer_ex; import java.io ...

  4. android自动登录简书,Android开发之简单登录界面

    用户界面基础 Android系统的四大组件分别是活动(Activity).服务(Service).广播接收器(Broadcast Receiver).内容提供器(Content Provider). ...

  5. android 自动备份到局域网,Android和PC端通过局域网文件同步

    本文为大家分享了Android和PC端通过局域网文件同步的具体代码,供大家参考,具体内容如下 public class FileOptions { public String name; public ...

  6. android自动切换暗色,超实用!Android 深色模式适配(可定时开启的APP内主题切换管理工具)...

    前言 前面分享了一篇"黑白化主题"的文,主要适用场景是不久就要到来的"清明"等时节或者是其他的国家公祭日什么的(一名成熟的程序员,要学会自己提产品需求). 今天 ...

  7. android自动登录简书,android 手机号实现登录功能

    先看看效果 image.png 我的这个登录功能是手机号和密码都已经在后台数据库有存储的,所以是直接登录. 重点有三个: 1.账号密码的存储,实现自动登录: 2.网络通信: 3.密码一定要Md5加密之 ...

  8. Android自动待机和唤醒,Android深度睡眠和唤醒锁

    我创建了一个在所有手机上均可正常运行的android应用.但是在我的阿尔卡特手机中,手机无法进入深度睡眠模式,且数据网络出现故障,因此应用程序无法获取数据网络,也无法同步服务器数据. 我的设计 - S ...

  9. android 自动补全方法,Android零基础入门|自动完成文本框AutoCompleteTextView

    原标题:Android零基础入门|自动完成文本框AutoCompleteTextView 上一期学习的Spinner的使用,掌握的怎么样?本期一起来学习AutoCompleteTextView的使用. ...

  10. android自动拨号 代码,在Android上,是否有一种方法可以强行自动自动拨号?_android_开发99编程知识库...

    我一直在研究一个 Android 应用 概念,在用户启动服务时,应用程序必须自动拨号. 我发现,当应用程序尝试自动拨号时,手机( 还是叫 Intent ) 不会自动拨号,而用户必须手动启动服务. 目前 ...

最新文章

  1. 【Linux】—— /usr/bin/perl 被 MySQL-community-server-8.0.26-1.el7.x86_64 需要,解决方法
  2. PHP json_encode不转义中文
  3. 计算机常用的矢量图形文件,学位计算机考试2
  4. linux该专接本还是工作_是该专接本还是直接工作?学历和经验哪个重要?
  5. windows Hyper-V Server 2012创建脚本运行环境
  6. How does framework require TechnicalInfo.js
  7. sql 查询结果自定义排序
  8. hadoop集群的搭建(分布式安装)
  9. matlab中a k,Python:相当于Matlab的大型数组的svds(A,k)?
  10. Android SDK下载太慢
  11. 西门子S7-1200PLC脉冲控制伺服程序案例 此程序是关于西门子1200PLC以PTO脉冲方式控制伺服电机,步进电机的功能块程序
  12. 线性同余法生成随机数Matlab_生成安全的随机数
  13. netty原理之蔚蓝天空
  14. 2020年最新PHP面试题汇总(附答案)
  15. SA-NET: Shuffle attention for DCNN 论文学习
  16. 由内而外全面造就自己(一)
  17. BackTrack5里使用OpenVAS
  18. 史上最通俗计算机网络分层详解,附架构师必备技术详解
  19. PowerBI-时间智能函数-LAST系列
  20. Palm软件TOP10排行榜

热门文章

  1. 江西理工大学校园网开机自动连接,断网自动重连
  2. 使用Route报错:A <Route> is only ever to be used as the child of <Routes> element, never rendered directl
  3. linux用户motd,linux – 每个用户的SSH MOTD
  4. load_weights` requires h5py when loading weights from HDF5
  5. python爬千图网高清图片
  6. java实现rabbitmq_RabbitMQ搭建(2)-Java简单实现
  7. p5.js 和 Processing 的恩怨情仇
  8. matlab rho是什么意思,什么是Rho值
  9. 科技爱好者周刊(第 108 期):阵地战与奇袭战
  10. vue创建一个简易版高德地铁路线图