美文网首页
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