Android主题切换—夜间/白天模式探究
现在市面上众多阅读类App都提供了两种主题:白天or夜间。
上述两幅图片,正是两款App的夜间模式效果,所以,依据这个功能,来看看切换主题到底是怎么实现的(当然现在github有好多PluginTheme开源插件,很多时候可以使用这些插件,不过我并不想讲怎么用那些插件,正所谓会用轮子还不如会造轮子)。
关于更换主题和换肤
这里提到是做换主题功能,当然与之类似的就是换肤,换肤现在比较流行的是采用插件化动态加载技术来实现的,这样可以起到热插拔作用,需要皮肤时候用户自主的在网上下载便是了,不用皮肤时便删了皮肤插件包而不会影响宿主App的功能,这样就不必把一大堆皮肤图片放在本地而增加apk的大小,关于用插件化实现换肤功能这仅仅是插件化技术的冰山一角,关于插件化技术更多的作用,可以看看360前两天开源的 DroidPlugin插件框架、OpenAltas框架、还有主席的DL框架。
好了,言归正传,现在我们需要实现的是主题切换功能,关于主题切换其实是切换整个App的颜色风格、排版风格、字体风格等,其中并不会有过多的图片资源的切换,如有过多的图片的更换那就是换肤的功能了。
现在我们要实现夜间/白天模式的切换功能,如下效果图:
可以看到上面的效果正是夜间和白天两种模式的切换功能,切换至夜间模式时整个App的背景色、字体颜色、按钮颜色、标题栏颜色等全部需要切为夜间模式的颜色,当切回白天模式又切回原来的颜色,来看看怎么做的?
实现主题切换
首先就是需要在app中准备两套主题:
白天主题
<resources>
<style name="DayTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#03A9F4</item>
<item name="android:textColorPrimary">#ffffff</item>
<item name="android:windowBackground">@color/background_material_light</item>
<item name="colorAccent">#00BCD4</item>
<item name="colorControlNormal">#00BCD4</item>
<item name="titleStyle">@style/DayTitleStyle</item>
<item name="contentStyle">@style/DayContentStyle</item>
<item name="buttonBg">#2196F3</item>
<item name="buttonTextColor">#ffffff</item>
<item name="checkTextColor">#2196F3</item>
<item name="switchTextColor">#2196F3</item>
</style>
<style name="DayTitleStyle">
<item name="android:textColor">#212121</item>
<item name="android:textSize">20sp</item>
<item name="android:layout_margin">8dp</item>
</style>
<style name="DayContentStyle">
<item name="android:textColor">#9C27B0</item>
<item name="android:textSize">16sp</item>
<item name="android:layout_margin">16dp</item>
<item name="android:maxLines">10</item>
</style>
</resources>
夜间主题
<resources>
<style name="NightTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#00796B</item>
<item name="android:textColorPrimary">#212121</item>
<item name="android:windowBackground">@color/background_material_dark</item>
<item name="colorAccent">#00796B</item>
<item name="colorControlNormal">#212121</item>
<item name="titleStyle">@style/NightTitleStyle</item>
<item name="contentStyle">@style/NightContentStyle</item>
<item name="buttonBg">#00796B</item>
<item name="buttonTextColor">#9E9E9E</item>
<item name="checkTextColor">#212121</item>
<item name="switchTextColor">#212121</item>
</style>
<style name="NightTitleStyle">
<item name="android:textColor">#212121</item>
<item name="android:textSize">20sp</item>
<item name="android:layout_margin">8dp</item>
</style>
<style name="NightContentStyle">
<item name="android:textColor">#212121</item>
<item name="android:textSize">16sp</item>
<item name="android:layout_margin">16dp</item>
<item name="android:maxLines">10</item>
</style>
</resources>
上面这两套主题中,各个属性定义完全一模一样,不一样的只是属性的值,其中在DayTheme和NightTheme的style中有这么一段代码:
<item name="titleStyle">@style/DayTitleStyle</item>
<item name="contentStyle">@style/DayContentStyle</item>
<item name="buttonBg">#2196F3</item>
<item name="buttonTextColor">#ffffff</item>
<item name="checkTextColor">#2196F3</item>
<item name="switchTextColor">#2196F3</item>
正常情况下style中是不存在这些属性的,它们这些是自定义属性,主要是用来控制某些控件或者布局的属性,它们的定义在attr文件中:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="contentStyle" format="reference"/>
<attr name="titleStyle" format="reference"/>
<attr name="buttonBg" format="reference|color"/>
<attr name="buttonTextColor" format="reference|color"/>
<attr name="checkTextColor" format="reference|color"/>
<attr name="switchTextColor" format="reference|color"/>
</resources>
然后在布局中引用即可:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
style="?attr/titleStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title" />
<TextView
style="?attr/contentStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox"
android:textColor="?attr/checkTextColor" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox"
android:textColor="?attr/checkTextColor" />
<Switch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch"
android:textColor="?attr/switchTextColor" />
<Button
android:id="@+id/btn_setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="设置"
android:background="?attr/buttonBg"
android:textColor="?attr/buttonTextColor" />
</LinearLayout>
最后在整个App主题的style中使用它们就ok了。这样做有什么好处呢?我们都知道App设置主题时候都是设置一个style,而App中某些控件或者布局的背景或者style样式需要和整个主题样式不同时,这时候可以通过设置个自定义属性,通过在App的style中给与自定义属性不同的值来达到目的。
切换主题
好了,有了两套主题了,接下来是通过代码来进行控制主题间的切换了,控制主题的切换其实就是通过setTheme(R.style.*);来设置不同的style从而达到界面风格的变换,不过这个方法setTheme()只在setContentView()方法前设置才有效,所以如果你想在其它地方调用这个方法来切换主题那是肯定不行的,所以这里有两个难点?
1、怎么处理当前的设置界面在切换主题后同时切换主题风格
2、怎么处理之前已经打开的界面让他们切换主题风格
这里我给出的答案是:
1、在当前切换主题的设置界面使用
Activity.recreate()方法,该方法的作用就是当当前Activity的配置发生变化时,调用这个方法可以把当前Activity实例销毁并重新创建出一个Activity实例。如此可见通过这个方法可以很容易的解决问题一,因为它会重新创建一个新的Activity实例。2、这里我使用的方法是通过设置Intent的Flag来达到更新之前Activity的效果,通过设置
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);让它清除之前的Activity再创建一个新的Activity,这样当返回之前的界面就可以更新主题了。【注】如果有多个界面可以通过设置主界面MainActivity的launchMode为singleTask,在返回主界面时候清除其它界面来更新主题
对于上面的方法(如有更好的方法欢迎告知,万分感谢!)
代码实现
最后再贴下代码:
通过一个主题设置工具类设置主题,在每个Activity的setContentView()方法之前设置主题:
设置主题工具类:
public class ThemeChangeUtil {
public static boolean isChange = false;
public static void changeTheme(Activity activity){
if(isChange){
activity.setTheme(R.style.NightTheme);
}
}
}
设置界面:
public class ChangeTheme extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
ThemeChangeUtil.changeTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_change);
Button mChangeBtn = (Button) findViewById(R.id.btn_change);
mChangeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ThemeChangeUtil.isChange) {
ThemeChangeUtil.isChange = false;
} else {
ThemeChangeUtil.isChange = true;
}
ChangeTheme.this.recreate();//重新创建当前Activity实例
}
});
}
@Override
public void onBackPressed() {
super.onBackPressed();
Intent mIntent = new Intent(this, MainActivity.class);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(mIntent);
finish();
}
}
主界面:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
ThemeChangeUtil.changeTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mSettingBtn = (Button) findViewById(R.id.btn_setting);
mSettingBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.this.startActivity(new Intent(MainActivity.this, ChangeTheme.class));
}
});
}
}
Demo下载
Android主题切换—夜间/白天模式探究的更多相关文章
- Android 主题切换 小结
前言 我们用手机的时候经常看到 设置里面有夜间模式和白天模式来更换APP的主题,以前以为很简单,但是实际做起来还是有各种不完美,那么我们也要去了解各种解决方案来丰富我们的知识,现在我们就来看看各种优劣 ...
- Android DevArt3:SingleTask启动模式探究:首先从MainActivity启动案例入口AActivity,并在A中启动BActivity,从B启动CActivity, 再从C中又启动AActivity, 最后在A中启动B,现在按两次back键,然后回到的是哪个Activity? 答案是,回到MainActivity。
SingleTask启动模式探究 GitHub如题:首先从MainActivity启动案例入口AActivity,并在A中启动BActivity,从B启动CActivity,再从C中又启动AActiv ...
- Android主题切换方案总结
所谓的主题切换,就是能够根据不同的设定,呈现不同风格的界面给用户,也就是所谓的换肤. 1.将主题包(图片与配置)存到SD卡上(可通过下载或手动放入指定目录),在代码里强制从本地文件创建图片与配置文字大 ...
- Android主题切换
一.APK文件方式:(CM9方案) 我们知道Android给每个APK进程分配一个单独的用户空间,其manifest中的userid就是对应一个Linux用户的(Android 系统是基于Linux) ...
- Android 实现切换主题皮肤功能(类似于众多app中的 夜间模式,主题包等)
首先来个最简单的一键切换主题功能,就做个白天和晚上的主题好了. 先看我们的styles文件: <resources> <!-- Base application theme. --& ...
- Android记录24-WebView实现白天/夜间阅读模式
前言 本篇博客给大家分享一个WebView的使用案例.实现Android调用JavaScript代码来控制白天/夜间模式. 关于WebView怎样使用,官网有非常好的说明,Building Web A ...
- Android 高级UI设计笔记24:Android 夜间模式之 WebView 实现白天 / 夜间阅读模式 (使用JavaScript)
1. 问题引入: 前面我们是使用方法 降低屏幕亮度(不常用) 和 替换theme,两者都是针对Activity的背景进行白天.夜间模式的交换,但是如果我们显示的是Html的内容,这个时候改怎么办? 分 ...
- Android 主题动态切换框架:Prism
Prism(棱镜) 是一个全新的 Android 动态主题切换框架,虽然是头一次发布,但它所具备的基础功能已经足够强大了!本文介绍了 Prism 的各种用法,希望对你会有所帮助,你也可以对它进行扩展, ...
- android简单的夜间模式
现在android项目values下打 attrs.xml <?xml version="1.0" encoding="utf-8"?> <r ...
随机推荐
- linux中 probe函数的何时调用的?
点击打开链接 linux中 probe函数何时调用的 所以的驱动教程上都说:只有设备和驱动的名字匹配,BUS就会调用驱动的probe函数,但是有时我们要看看probe函数里面到底做了什么,还有传递给p ...
- Java基本语法-----java变量
1.变量的概述 用于存储可变数据的容器. 2.变量存在的意义 计算机主要用于处理生活中的数据,由于生活中存在大量的可变数据,那么计算机就必须具备存储可变数据的能力. 比如: 1.时间每一秒都在发生变化 ...
- maven跳过单元测试的两个参数区别
maven在打包过程中需要执行单元测试.但有些时候单元测试已经通过只是想打包时,想跳过测试.maven提供了两个参数跳过测试:maven.test.skip=true 和skipTests. 例子 m ...
- Android开发学习之路--Annotation注解简化view控件之初体验
一般我们在写android Activity的时候总是会在onCreate方法中加上setContentView方法来加载layout,通过findViewById来实现控件的绑定,每次写这么多代码总 ...
- [ExtJS5学习笔记]第二节 Sencha Cmd 学习笔记 使你的sencha cmd跑起来
本文地址: http://blog.csdn.net/sushengmiyan/article/details/38313537 本文作者:sushengmiyan ----------------- ...
- NoSQL数据库之Redis数据库:Redis的介绍与安装部署
NoSQL(NoSQL = Not Only SQL),它指的是非关系型的数据库.随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的w ...
- 【一天一道LeetCode】#349. Intersection of Two Arrays
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given t ...
- UNIX网络编程——ICMP报文分析:端口不可达
ICMP的一个规则是,ICMP差错报文必须包括生成该差错报文的数据报IP首部(包含任何选项),还必须至少包括跟在该IP首部后面的前8个字节(包含源端口和目的端口).在我们的例子中,跟在IP首部后面的前 ...
- 网站开发进阶(三十八)Web前端开发规范文档你需要知道的事
Web前端开发规范文档你需要知道的事 规范目的 为提高团队协作效率, 便于后台人员添加功能及前端后期优化维护, 输出高质量的文档, 特制订此文档. 本规范文档一经确认, 前端开发人员必须按本文档规范进 ...
- Java进阶(二十六)公司项目开发知识点回顾
公司项目开发知识点回顾 前言 "拿来主义"在某些时候并不是最佳选择,尤其是当自己遇到问题的时候,毫无头绪. 在一次实验过程中,需要实现数据库的CRUD操作.由于之前项目开发过程中, ...