美文网首页
Android夜间模式

Android夜间模式

作者: 馒头炖土豆 | 来源:发表于2023-04-17 18:41 被阅读0次

    参考链接:

    链接1

    链接2

    最近公司想做夜间模式,于是在网上进行了搜索,发现一些三方库已经很久不更新了,于是转而参考上面的两个链接,利用系统特性研究出一套夜间模式的方法,这套方法代码量比较小,适用性强,能够很好的满足我司当前的需求;

    开发思路:我最开始看到的是链接1,然后根据链接1开搞的过程中发现,里面的示例代码不全,在xml中设置的字体颜色无法修改,本人能力有限,百度之后也无法解决这个问题,于是转而看网上的其他方法并找到了链接2,通过实践发现链接2可以很好的修改xml中设置的背景色和字体色以及自定义drawable背景中的颜色,完美弥补了链接1的不足,但是链接2不能对代码中动态设置的字体颜色和背景色进行修改,而链接1又很好的完成了这一点;于是二者结合,成功解决夜间模式问题

    总结:

    链接1:负责修改代码中动态设置的字体颜色和背景色;
    链接2:负责修改 xml 和 drawable 中设置的字体颜色和背景色;

    链接1的实现思路:

    1:创建res-night文件夹,注意一定要和 res 文件夹是同级:


    image.png

    2:在build.gradle中 android{} 下添加以下代码:

    //适配暗黑模式
        sourceSets {
            main {
                java {
                    srcDir 'src/main/java'
                }
                res.srcDirs += 'src/main/res'
                res.srcDirs += 'src/main/res-night'
            }
        }
    

    3:在Application类中添加以下代码:

     private  Resources mSkinResources = null;
    
     @Override
        public Resources getResources() {
            if (mSkinResources == null) {
                mSkinResources = new SkinResources(this,super.getResources());
            }
            return mSkinResources;
        }
    
    

    4:SkinResources 类源码:

    class SkinResources(context: Context, res: Resources) : Resources(res.assets, res.displayMetrics, res.configuration) {
    
        val contextRef: WeakReference<Context> = WeakReference(context)
    
        override fun getDrawableForDensity(id: Int, density: Int, theme: Theme?): Drawable? {
            return super.getDrawableForDensity(resetResIdIfNeed(contextRef.get(), id), density, theme)
        }
    
        override fun getColor(id: Int, theme: Theme?): Int {
            return super.getColor(resetResIdIfNeed(contextRef.get(), id), theme)
        }
    
        override fun getColorStateList(id: Int, theme: Theme?): ColorStateList {
            return super.getColorStateList(resetResIdIfNeed(contextRef.get(), id), theme)
        }
    
        private fun resetResIdIfNeed(context: Context?, resId: Int): Int {
            // 非暗黑无需替换资源 ID
            val boolean = SPUtils.getBoolean(context, "mode", false) //默认为白天模式
    
            if (context == null || !boolean)
            {
                return resId
            }
            var newResId = resId
            val res = context.resources
            try {
                val resPkg = res.getResourcePackageName(resId)
                // 非本包资源无需替换
                if (context.packageName != resPkg) return newResId
    
                val resName = res.getResourceEntryName(resId)
                val resType = res.getResourceTypeName(resId)
                // 获取对应暗黑皮肤的资源 id
                val id = res.getIdentifier("${resName}_night", resType, resPkg)
    
                if (id != 0) newResId = id
            } finally {
                return newResId
            }
        }
    }
    

    5:给 res-night 文件夹中的colors文件添加颜色,具体要映射多少颜色,需要根据项目情况来定,这里举例如下:
    res 文件夹中colors中的白色:

        <color name="white">#ffffff</color>
    

    在这里应该是:

           <color name="white_night">#000000</color>
    

    到此为止链接1中需要做的事情已经做完了,下面是链接2中的步骤:

    1:在Application类的onCreate()中添加以下代码:

          boolean isNight = SPUtils.getBoolean(this, "mode", false); //默认为白天模式
          if (isNight)
            {
                //这个方法一设置就会全局生效,但是只能作用于xml中,对于代码中动态设置的颜色无效
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            }else {
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            }
    

    2:在res文件夹下创建values-night文件夹,如下:


    image.png

    3:colors文件中颜色对应如下:

        <color name="white">#ffffff</color>
    

    在这里应该是:

           <color name="white">#000000</color>
    

    到此为止链接2中需要做的事情已经做完了,下面是暗黑模式的开关部分:

    val isNight = SPUtils.getBoolean(this, "mode",false)
    SPUtils.put(this,"mode",!isNight)
    if (!isNight)
       {
              //这个方法一设置就会全局生效,但是只能作用于xml中,对于代码中动态设置的颜色无效
              AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
        }else{
               AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
       }
    

    到此为止暗黑模式就基本完成了,剩下的就是一些效果的优化,比如开关暗黑模式时当前页面会闪烁,这个在链接2中有解决方法,可以自行参考,如有其他问题可以留言;最后赠人玫瑰,手留余香,参考完记得点赞+关注

    相关文章

      网友评论

          本文标题:Android夜间模式

          本文链接:https://www.haomeiwen.com/subject/pbxcjdtx.html