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实战:夜间模式实现方法一相关推荐

  1. android 夜间模式蒙板,常见APP的夜间模式梳理和设计方法

    本文笔者将对一些APP的夜间模式进行分析,总结夜间模式常见的切换方式,以及从简单到复杂的几种夜间模式设计方法. 一.夜间模式的由来和作用 最早应该是智能手机的普及大大延迟了人们的睡眠时间,大家都习惯晚 ...

  2. 一种简单快速的方式实现 Android App 的夜间模式

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

  3. iphone如何设置微信腾讯服务器,iPhone手机的微信怎么设置成夜间模式?

    而日常在使用iPhone手机聊微信时,你有没有遇到这样的问题.就是当我们在关灯后,如果还再用微信聊天的话,手机屏幕的亮度会觉得很刺眼,使用时间一长就会很不舒服. 那么,此时开启iPhone手机微信的夜 ...

  4. 集设作品灵感|App夜间模式如何设计?

    不同类型的 App 对于夜间模式的需求程度是不同的,通过降低对比度和亮度.将背景增加为深色减少光通量,在较暗环境下可以有效减少刺眼等不良体验.集设网 www.ijishe.com设计师交流社区精选了 ...

  5. 灵感|APP夜间模式如何设计?

    不同类型的 App 对于夜间模式的需求程度是不同的,通过降低对比度和亮度.将背景增加为深色减少光通量,在较暗环境下可以有效减少刺眼等不良体验.集设网 www.ijishe.com 设计师交流学习社区精 ...

  6. android官方夜间模式,Android夜间模式实践

    前言 由于项目需要,近段时间开发的夜间模式功能.主流的方案如下: 1.通过切换theme实现 2.通过resource id映射实现 3.通过Android Support Library的实现 方案 ...

  7. Android夜间模式实践

    前言 由于项目需要,近段时间开发的夜间模式功能.主流的方案如下: 1.通过切换theme实现 2.通过resource id映射实现 3.通过Android Support Library的实现 方案 ...

  8. android studio夜间模式,android studio怎样实现夜间模式

    满意答案 noxlqub 2016.05.01 采纳率:51%    等级:7 已帮助:210人 关于阅读类的app,有个夜间模式真是太重要了. 那么有两种方式可以实现夜间模式 1:修改theme,重 ...

  9. 微信相册服务器偷懒,微信不做纯属偷懒?这款夜间模式神器刷新你三观

    [PConline 应用]微信的夜间模式终于是来了.为了适配iOS的开发政策,最新在App Store上架的微信,总算是加入了夜间模式.要知道,微信一直以来坚持自己的想法,对夜间模式无动于衷,大家等了 ...

最新文章

  1. 关于写代码的几个看法
  2. hdu 3416(最短路+最大流)
  3. ST_Geometry操作报ora-01704字符串文字太长
  4. 微信支付宝服务器在哪里,支付宝支付与微信支付服务端回调notify_url数据的区别...
  5. 2021技术人新展望
  6. 使用NetBeans Lambda支持在Java 8中使用Lambda表达式对列表进行排序
  7. Linux 文件与目录管理、ls、cd、pwd、mkdir、rmdir、cp、 rm
  8. 发生一个未处理的异常 脚本调试 错误号2912
  9. uFrame近况(2016年4月8日更新)
  10. 学会这篇文章分享的知识,你就超过了90%的测试人
  11. 不能使用 float 和 double 来表示金额等精确的值
  12. jquery 实现图片上传,并在前端显示出来
  13. C语言——冒泡排序法,数组
  14. java 死循环排查_java2如何排查线上死循环
  15. java技术--报警通知及实现方式
  16. JavaWeb项目----实现用户登录、注册、对商品信息进行的添加、删除、修改功能
  17. 射频标签技术特征的分类
  18. 29 Linux 防火墙
  19. 基于Matlab的各地阳光强度计算
  20. EMC VNX5400 File NAS证书过期问题

热门文章

  1. Python打包exe程序(pyinstaller)以及打包文件太大的解决方法
  2. mvc5 ajax post json,mvc5 webap2 前台如何使用 ajax 请求后台API
  3. 生存模型的C-index(C指数)
  4. 攻击者如何破坏无人机?
  5. 行人重识别(21)——行人重识别算法性能指标
  6. 大中型企业敏捷转型策略路线图-案例解析
  7. 【vue项目实战】如何使用icon图标
  8. 渡鸦币RVN/乌鸦RVN登录龙网bitalong
  9. 面试官:说一下你们线上JVM是如何优化的?一不小心聊了2个小时!!
  10. 基于Glodstein枝切法相位解包裹算法