App实战:夜间模式实现方法一
App实战:夜间模式实现方法一
大致上有三种实现方法:
- 通过更换主题,不需要重新创建Activity。
/*** Set the base theme for this context. Note that this should be called* before any views are instantiated in the Context (for example before* calling {@link android.app.Activity#setContentView} or* {@link android.view.LayoutInflater#inflate}).** @param resid The style resource describing the theme.*/
public abstract void setTheme(@StyleRes int resid);
通过自带sdk提供的api,比较简单,需要重新创建Activity。
/** * Sets the default night mode. This is used across all activities/dialogs but can be overridden * locally via {@link #setLocalNightMode(int)}. * * <p>This method only takes effect for those situations where {@link #applyDayNight()} works. * Defaults to {@link #MODE_NIGHT_NO}.</p> * * <p>This only takes effect for components which are created after the call. Any components * which are already open will not be updated.</p> * * @see #setLocalNightMode(int) * @see #getDefaultNightMode() */ public static void setDefaultNightMode(@NightMode int mode) {switch (mode) {case MODE_NIGHT_AUTO:case MODE_NIGHT_NO:case MODE_NIGHT_YES:case MODE_NIGHT_FOLLOW_SYSTEM:sDefaultNightMode = mode;break;default:Log.d(TAG, "setDefaultNightMode() called with an unknown mode");break;} }
然后调用recreate(); 重新创建Activity。
自定义各种View继承自系统View,然后自定义方法设置夜间背景颜色,工作量巨大。
下面介绍第一种实现。
第一种开源方案来自何红辉Colorful。
利用context.setTheme新的主题后,然后通过循环遍历页面中的控件,通过如下代码获取新的颜色:
/*** @param newTheme* @return*/
protected int getColor(Theme newTheme)
{//返回重新指定后的资源idTypedValue typedValue = new TypedValue();newTheme.resolveAttribute(mAttrResId, typedValue, true);return typedValue.data;
}
所以基于以上的思想,在编写xml文件的时候,给view设置背景颜色或者给textview设置文字颜色时,就不能写死了。所以有以下几个步骤:
1.自定义view的背景参数如下:
<?xml version="1.0" encoding="utf-8"?>
<resources><attr name="root_view_bg" format="reference|color"/><attr name="cardview_bg" format="reference|color"/><attr name="toolbar_bg" format="reference|color"/><attr name="one_text_bg" format="reference|color"/><attr name="two_text_bg" format="reference|color"/></resources>
2.然后需要在colors文件中设置两套颜色,分别开头以day和night来区分,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<resources><color name="colorPrimary">#3F51B5</color><color name="colorPrimaryDark">#303F9F</color><color name="colorAccent">#FF4081</color>//日间模式的颜色<color name="day_root_view_bg">#F0F7EF</color><color name="day_card_view_bg">#F0F7EF</color><color name="day_one_text_bg">#353535</color><color name="day_two_text_bg">#9e9e9e</color><color name="day_toolbar_bg">#3F51B5</color>//夜间模式的颜色<color name="night_root_view_bg">#3b3838</color><color name="night_card_view_bg">#3b3838</color><color name="night_one_text_bg">#BEBBBB</color><color name="night_two_text_bg">#9e9e9e</color><color name="night_toolbar_bg">#3b3838</color><color name="white">#ffffff</color></resources>
3.然后定义两个主题DayTheme和NightTheme,代码如下所示:
<style name="DayTheme" parent="NoBarTheme"><item name="root_view_bg">@color/day_root_view_bg</item><item name="cardview_bg">@color/day_card_view_bg</item><item name="one_text_bg">@color/day_one_text_bg</item><item name="two_text_bg">@color/day_two_text_bg</item><item name="toolbar_bg">@color/day_toolbar_bg</item>
</style><style name="NightTheme" parent="NoBarTheme"><item name="root_view_bg">@color/night_root_view_bg</item><item name="cardview_bg">@color/night_card_view_bg</item><item name="one_text_bg">@color/night_one_text_bg</item><item name="two_text_bg">@color/night_two_text_bg</item><item name="toolbar_bg">@color/night_toolbar_bg</item>
</style>
4.在编写xml文件中,背景颜色应该这么写比如:?attr/toolbar_bg:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".ui.NightModeActivity"><android.support.v7.widget.Toolbar
android:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="?attr/actionBarSize"android:background="?attr/toolbar_bg"app:navigationIcon="@mipmap/back"app:title="夜间模式"app:titleTextColor="@color/white"/><android.support.v7.widget.RecyclerView
android:id="@+id/night_rv"android:layout_width="match_parent"android:layout_height="match_parent"android:background="?attr/root_view_bg"/>
</LinearLayout>
5.然后就是在Activity中的代码。
a.首先setTheme方法说的很清楚,需要在setContentView调用之前调用。所以会有
initTheme();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_night_mode);
b.初始化Colorful,代码如下:
private void setupColorful()
{ViewGroupSetter toolbarSetter = new ViewGroupSetter(mToolbar, R.attr.toolbar_bg);ViewGroupSetter rvSetter = new ViewGroupSetter(mNightRv, R.attr.root_view_bg);rvSetter.childViewTextColor(R.id.category_desc, R.attr.one_text_bg);rvSetter.childViewTextColor(R.id.category_author, R.attr.two_text_bg);rvSetter.childViewTextColor(R.id.category_date, R.attr.two_text_bg);rvSetter.childViewBgColor(R.id.night_rl, R.attr.cardview_bg);colorful = new Colorful.Builder(this).setter(toolbarSetter).setter(rvSetter).create();}
代码很简单,构造方法ViewSetter两个参数分别表示目标View和与其对应的特定属性id。如果目标view是ViewGroup类并且有子View需要指定特定属性id,则需要调用childViewTextColor或者childViewBgColor,两个参数分别代表绑定id和与其对应的特定属性。
再加一个转换模式的代码:
private void switchMode()
{if (!mPref.getBoolean(NIGHT, false)){colorful.setTheme(R.style.NightTheme);mPref.edit().putBoolean(NIGHT, true).commit();} else{colorful.setTheme(R.style.DayTheme);mPref.edit().putBoolean(NIGHT, false).commit();}
}
来看一下效果:
可以看到有两个明显的缺陷:
- 就是状态栏的颜色并没有跟随改变;
- 颜色变化过于突兀;
针对问题一:引入猴哥的状态栏的库StatusBarUtil,可以解决问题。
针对问题二:可以利用属性动画来解决这个过于生硬的主题切换问题,思路如下:
首先获取当前窗口的根布局,利用这个根布局创建一个bitmap。然后创建一个临时View,并利用这个bitmap给这个临时View设置和当前根布局一样的背景。然后再来一个逐渐透明的动画,因为主题切换其实是瞬间切好,但是有了这个动画,就 给人的感觉是过度变化的。b话不多说,代码如下:
/*** 给夜间模式增加一个动画,颜色渐变** @param newTheme*/
private void animChangeColor(final int newTheme)
{final View rootView = getWindow().getDecorView();rootView.setDrawingCacheEnabled(true);rootView.buildDrawingCache(true);final Bitmap localBitmap = Bitmap.createBitmap(rootView.getDrawingCache());rootView.setDrawingCacheEnabled(false);if (null != localBitmap && rootView instanceof ViewGroup){final View tmpView = new View(this);tmpView.setBackgroundDrawable(new BitmapDrawable(getResources(), localBitmap));ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);((ViewGroup) rootView).addView(tmpView, params);tmpView.animate().alpha(0).setDuration(400).setListener(new Animator.AnimatorListener(){@Overridepublic void onAnimationStart(Animator animation){colorful.setTheme(newTheme);System.gc();}@Overridepublic void onAnimationEnd(Animator animation){((ViewGroup) rootView).removeView(tmpView);localBitmap.recycle();}@Overridepublic void onAnimationCancel(Animator animation){}@Overridepublic void onAnimationRepeat(Animator animation){}}).start();}
}
然后来看下最终的效果图:
可以看到两个问题都已经解决了。
Github Demo。帮我点赞啊。
上一篇博客:
App架构设计实战二:基于MVP模式的相似UI界面复用问题解决方案
下一篇博客:
App实战:权限管理再封装之一键调用
App实战:夜间模式实现方法一相关推荐
- android 夜间模式蒙板,常见APP的夜间模式梳理和设计方法
本文笔者将对一些APP的夜间模式进行分析,总结夜间模式常见的切换方式,以及从简单到复杂的几种夜间模式设计方法. 一.夜间模式的由来和作用 最早应该是智能手机的普及大大延迟了人们的睡眠时间,大家都习惯晚 ...
- 一种简单快速的方式实现 Android App 的夜间模式
博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此 博主:威威喵 | 博客主页:https://blog.csdn.net/ ...
- iphone如何设置微信腾讯服务器,iPhone手机的微信怎么设置成夜间模式?
而日常在使用iPhone手机聊微信时,你有没有遇到这样的问题.就是当我们在关灯后,如果还再用微信聊天的话,手机屏幕的亮度会觉得很刺眼,使用时间一长就会很不舒服. 那么,此时开启iPhone手机微信的夜 ...
- 集设作品灵感|App夜间模式如何设计?
不同类型的 App 对于夜间模式的需求程度是不同的,通过降低对比度和亮度.将背景增加为深色减少光通量,在较暗环境下可以有效减少刺眼等不良体验.集设网 www.ijishe.com设计师交流社区精选了 ...
- 灵感|APP夜间模式如何设计?
不同类型的 App 对于夜间模式的需求程度是不同的,通过降低对比度和亮度.将背景增加为深色减少光通量,在较暗环境下可以有效减少刺眼等不良体验.集设网 www.ijishe.com 设计师交流学习社区精 ...
- android官方夜间模式,Android夜间模式实践
前言 由于项目需要,近段时间开发的夜间模式功能.主流的方案如下: 1.通过切换theme实现 2.通过resource id映射实现 3.通过Android Support Library的实现 方案 ...
- Android夜间模式实践
前言 由于项目需要,近段时间开发的夜间模式功能.主流的方案如下: 1.通过切换theme实现 2.通过resource id映射实现 3.通过Android Support Library的实现 方案 ...
- android studio夜间模式,android studio怎样实现夜间模式
满意答案 noxlqub 2016.05.01 采纳率:51% 等级:7 已帮助:210人 关于阅读类的app,有个夜间模式真是太重要了. 那么有两种方式可以实现夜间模式 1:修改theme,重 ...
- 微信相册服务器偷懒,微信不做纯属偷懒?这款夜间模式神器刷新你三观
[PConline 应用]微信的夜间模式终于是来了.为了适配iOS的开发政策,最新在App Store上架的微信,总算是加入了夜间模式.要知道,微信一直以来坚持自己的想法,对夜间模式无动于衷,大家等了 ...
最新文章
- 关于写代码的几个看法
- hdu 3416(最短路+最大流)
- ST_Geometry操作报ora-01704字符串文字太长
- 微信支付宝服务器在哪里,支付宝支付与微信支付服务端回调notify_url数据的区别...
- 2021技术人新展望
- 使用NetBeans Lambda支持在Java 8中使用Lambda表达式对列表进行排序
- Linux 文件与目录管理、ls、cd、pwd、mkdir、rmdir、cp、 rm
- 发生一个未处理的异常 脚本调试 错误号2912
- uFrame近况(2016年4月8日更新)
- 学会这篇文章分享的知识,你就超过了90%的测试人
- 不能使用 float 和 double 来表示金额等精确的值
- jquery 实现图片上传,并在前端显示出来
- C语言——冒泡排序法,数组
- java 死循环排查_java2如何排查线上死循环
- java技术--报警通知及实现方式
- JavaWeb项目----实现用户登录、注册、对商品信息进行的添加、删除、修改功能
- 射频标签技术特征的分类
- 29 Linux 防火墙
- 基于Matlab的各地阳光强度计算
- EMC VNX5400 File NAS证书过期问题