【android】夜间模式简单实现
完整代码,请参考我的博客园客户端,git地址:http://git.oschina.net/yso/CNBlogs
关于阅读类的app,有个夜间模式真是太重要了。
那么有两种方式可以实现夜间模式
1:修改theme,重启activity
优点:正儿八经的夜间模式,配色看着舒服
缺点:图片刺眼、闪屏
核心思路:自定义一个颜色属性名 A,A在日间和夜间模式下都有具体的颜色代码,页面布局文件只管引用A,至于是日间还是夜间,由后台主题决定。
2:使用一个带黑色带透明度的View,盖在现有的activity上,效果类似你带上墨镜,看着太阳不刺眼。
优点:不用重启activity,不闪屏;加上透明度过渡动画,模式之间切换非常舒服,解决了1中,白底图片依旧刺眼的问题。;
缺点:配色没变化,就算带上墨镜,白天依旧是白天。
核心思路:使用WindowManager,在当前activity上,通过addView,添加一个黑色带透明度的View。
本方案整合了两种解决方案。在夜间配色的基础上,再加上一层墨镜,让图片也变得柔和起来,效果图如下:
可以看待chrome图标的白色底,在夜间模式下也变得柔和了


好,下面来讲讲具体的实现步骤,本环节使用的开发环境是android Studio
1 首先,在values下要准备好三个文件,没有就自己创建

attrs.xml(声明属性的类型,布局xml中用) reference可以使用系统的资源ID,比如R.color.gray; color可以直接使用#ffffff颜色代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="containerBackground" format="reference|color"></attr>
<attr name="cardBackground" format="reference|color"></attr>
<attr name="titleColor" format="reference|color"></attr>
<attr name="textColor" format="reference|color"></attr>
<attr name="selectorBtn" format="reference"></attr>
<attr name="selectorListItem" format="reference"></attr>
</resources>
colors.xml(调色板,集中管理颜色hex)遵循优秀格式规范,即调色板模式,避免使用btn1,btn2,fontTitle,fontText之类的颜色名。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="white">#fafafa</color>
<color name="white_dark">#f3f3f3</color> <color name="gray_light">#cccccc</color>
<color name="gray">#777</color>
<color name="gray_dark">#383838</color> <color name="green_light">#8e9ea4</color>
<color name="green">#34515c</color>
<color name="green_dark">#1e3e4a</color> <color name="night_mask">#90000000</color>
</resources>
styles.xml(日间、夜间主题)
<resources>
<!-- Application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> </style>
<!-- 日间模式 -->
<style name="AppTheme.day" parent="AppTheme">
<item name="containerBackground">@color/white_dark</item>
<item name="titleColor">@color/gray_dark</item>
<item name="textColor">@color/gray</item>
<item name="selectorBtn">@drawable/navigator_list_item_day</item>
<item name="selectorListItem">@drawable/list_item_day</item>
</style>
<!-- 夜间模式 -->
<style name="AppTheme.night" parent="AppTheme">
<item name="containerBackground">@color/green_dark</item>
<item name="titleColor">@color/white_dark</item>
<item name="textColor">@color/green_light</item>
<item name="selectorBtn">@drawable/navigator_list_item_night</item>
<item name="selectorListItem">@drawable/list_item_night</item>
</style>
</resources>
2定义activity父类,自动托管日间、夜间模式
BaseApplication就是自己包装的Application,通过它,保存日间、夜间模式
Application和Activity,Service一样是android框架的一个系统组件,当android程序启动时系统会创建一个 application对象,用来存储系统的一些信息。通常我们是不需要指定一个Application的,这时系统会自动帮我们创建,如果需要创建自己 的Application,也很简单创建一个类继承 Application并在manifest的application标签中进行注册(只需要给Application标签增加个name属性把自己的 Application的名字定入即可)。
android系统会为每个程序运行时创建一个Application类的对象且仅创建一个,所以Application可以说是单例 (singleton)模式的一个类.且application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。因为它是全局 的单例的,所以在不同的Activity,Service中获得的对象都是同一个对象。所以通过Application来进行一些,数据传递,数据共享 等,数据缓存等操作。
public class BaseActionBarActivity extends ActionBarActivity {
private BaseApplication mBaseApp = null;
private WindowManager mWindowManager = null;
private View mNightView = null;
private LayoutParams mNightViewParam;
private boolean mIsAddedView;
@Override
protected void onCreate(Bundle savedInstanceState) {
mBaseApp = (BaseApplication) getApplication();
if (mBaseApp.isNightMode())
setTheme(R.style.AppTheme_night);
else
setTheme(R.style.AppTheme_day);
super.onCreate(savedInstanceState);
mIsAddedView = false;
if (mBaseApp.isNightMode()) {
initNightView();
mNightView.setBackgroundResource(R.color.night_mask);
}
}
@Override
protected void onDestroy() {
if (mIsAddedView) {
mBaseApp = null;
mWindowManager.removeViewImmediate(mNightView);
mWindowManager = null;
mNightView = null;
}
super.onDestroy();
}
public void ChangeToDay() {
mBaseApp.setIsNightMode(false);
mNightView.setBackgroundResource(android.R.color.transparent);
}
public void ChangeToNight() {
mBaseApp.setIsNightMode(true);
initNightView();
mNightView.setBackgroundResource(R.color.night_mask);
}
/**
* wait a time until the onresume finish
*/
public void recreateOnResume() {
new Handler().postDelayed(new Runnable() {
public void run() {
recreate();
}
}, 100);
}
private void initNightView() {
if (mIsAddedView == true)
return;
mNightViewParam = new LayoutParams(
LayoutParams.TYPE_APPLICATION,
LayoutParams.FLAG_NOT_TOUCHABLE | LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
mNightView = new View(this);
mWindowManager.addView(mNightView, mNightViewParam);
mIsAddedView = true;
}
}
值得一提的是recreateOnResume()函数,因为是从Resume里面重建activity的(避免闪屏)此时,直接调用系统的recreate函数时,会报错,原因是resume还没执行完,就被recreate了,因此,我们函数需要延时一会,等待系统完成resume就好了。一般延时1毫秒就可以了,但是我的app里面用到抽屉式导航栏,保存的时间要长点。
准备工作到这里已经结束了。只要activity集成自该父类,就会自动托管日间、夜间模式了
3调用方式
在布局文件里,引用颜色的地方,我们使用问号来访问定义在styles.xml里面主题的属性。换句话说,这种方式的神奇之处在于,我在夜间主题、白天主题都定义了titleColor,布局只管引用titleColor,至于是白天的还是晚上的,则由activity的setTheme指定。
?表示引用属性
“?”引用主题属性,当您使用这个标记,你所提供的资源名必须能够在主题属性中找到,因为资源工具认为这个资源属性是被期望得到的,您不需要明确的指出它的类型
<TextView
android:id="@+id/base_swipe_item_title"
android:layout_width="0dp"
android:layout_height="100dp"
android:layout_weight="1"
android:gravity="left|center_vertical"
android:textColor="?titleColor"
android:textSize="21sp" />
子类只要调用ChangeToDay、ChangeToNight就可以完成模式的切换了。别忘了recreate activity来生效哦,实例代码如下:
void changeViewMode() {
boolean isNight = getMyApplication().isNightMode();
if (isNight)
ChangeToDay();
else
ChangeToNight();
recreate();
}
OK,如过你能坚持看到这里,说明阁下是有耐心的人,奉上一个彩蛋。
关于WebView网页如何实现日间、夜间模式。
这个问题比我们现象的要简单的多。因为网页么,在生成html内容时,只要根据日间、还是夜间模式,替换css路径为日间.css、夜间.css就好了。
栗子来了,瞧,就是这个"{style}",我们要替换的对象。
<html>
<head>
<title>Cnblogs</title>
<link rel="stylesheet" type="text/css" href="{style}"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,
minimum-scale=1.0, user-scalable=no"/>
</head>
在对webview加载内容文本时,替换该字符串的css
replace("{style}",baseApplication.isNightMode() ? "style_night.css" : "style_day.css")
结构如下:

切换主题如何避免闪屏
我们知道,通过reCreate(),来重启activity的时候,会闪屏;
那么 在切换之前,先截屏作为activity盖在当前的activity上面,然后重启activity,完毕之后,把盖着的activity通过alpha动画消失,这样切换主题动作就会变的很柔和了
【android】夜间模式简单实现的更多相关文章
- android夜间模式实现
一.概述 android夜间模式实现分为两大类 重启activity的实现 不重启activity的实现 二.正文 1.重启activity实现夜间模式[在界面文件中的实现部分] 1.1在attrs. ...
- Android 夜间模式changeskin小结
@author vivian8725118 @CSDN http://blog.csdn.net/vivian8725118 @简书 http://www.jianshu.com/p/832e9776 ...
- Android夜间模式的几种实现
一.直接修改widget颜色,这种方式实现起来最简单,但需要每个控件都去修改,太过复杂.例如: /** * 相应交互,修改控件颜色 * @param view */public void onMeth ...
- Android 高级UI设计笔记24:Android 夜间模式之 WebView 实现白天 / 夜间阅读模式 (使用JavaScript)
1. 问题引入: 前面我们是使用方法 降低屏幕亮度(不常用) 和 替换theme,两者都是针对Activity的背景进行白天.夜间模式的交换,但是如果我们显示的是Html的内容,这个时候改怎么办? 分 ...
- Android 高级UI设计笔记23:Android 夜间模式之 两种常用方法(降低屏幕亮度+替换theme)
1. 夜间模式 所谓的夜间模式,就是能够根据不同的设定,呈现不同风格的界面给用户,而且晚上看着不伤眼睛.特别是一些新闻类App实现夜间模式是非常人性化的,增强用户体验. 2. 我根据网上的资料 以及自 ...
- Android 夜间模式的实现
package com.loaderman.daynightdemo; import android.os.Bundle; import android.support.v7.app.AppCompa ...
- android MVP模式简单介绍
原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/ 前言 MVP作为一种MVC的演化版本在Android开发中受到 ...
- Android MVP模式简单介绍:以一个登陆流程为例
老的项目用的MVC的模式,最近完成了全部重构成MVP模式的工作,虽然比较麻烦,好处是代码逻辑更加清楚.简洁,流程更加清晰,对于后续版本迭代维护都挺方便.对于一些想要学习MVP模式的同学来讲,百度搜出来 ...
- android简单的夜间模式
现在android项目values下打 attrs.xml <?xml version="1.0" encoding="utf-8"?> <r ...
随机推荐
- freemarker3
结束标签 可以在结束标签中忽略user_def_dir_exp 也就是说可以写</@>来代替</@anything> 循环变量 <@myRepeatMacro count ...
- JavaScript------表单约束验证DOM方法
<input id="id1" type="number" min="100" max="300" require ...
- 2015 DevOps状态调查报告
依据Puppet Labs的2015 DevOps调查报告(下载地址:https://puppetlabs.com/2015-devops-report),调查研究表明: 拥有强IT服务绩效的企业一般 ...
- 编程之美 海量数据寻找 K 大数
1. 使用最小堆, 设置最小堆的大小为K, 仅需遍历一遍即可 2. 寻找最大的 K 个数实质上是寻找第 K 大的数. 通过二分法在区间内不断校正 mid 的值来找到 pivot, 时间复杂度为 o(N ...
- 复习及总结--.Net线程篇(4)
这里要说的就是多线程的锁的问题了 锁:作用在于实现线程间的同步问题,最典型的是售票问题 1,InterLocked 提供的都是静态方法,用来同步对多个共享变量的访问,包括以原子方式递增,递减,比较和替 ...
- Oracle sqlldr命令
今天别人的入库代码,看的真有点晕,最后看完才知道是用了sqlldr命令.哎...还是学艺不精啊,今后还是要多努力. 总结哈sqlldr命令:虽然大多是网上来的,自己要有体会嘛 !开源就是好啊. sql ...
- c#基础 第六讲
烧开水 先询问:“是否要烧开水(Y/N)” 是的话执行--0°--100°(30°---水温了,50°---水热了,80°---水快开了,100°---水已经开了, 结束.) 判断 循环 选择 跳转 ...
- 获取ScrollView的onScrollListener
scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() { @Overrid ...
- flask--简记
Jinjia变量过滤器: safe 渲染值时不转义 capitalize 把值的首字母转换成大写,其他字母转换成小写 lower 把值转换成小写形式 upper 把值转换成大写形式 title 把值中 ...
- Hibernate中的一些关键字理解
ORM的理解: ORM(Object/Relation Mapping): 对象/关系映射ORM 主要解决对象-关系的映射: ORM的思想:将关系数据库中表中的记录映射成为对象,以对象的形式展现,程序 ...