美文网首页Android技术知识Android开发经验谈Android开发
Android使用Window遮罩实现低成本夜间模式

Android使用Window遮罩实现低成本夜间模式

作者: fengmlo | 来源:发表于2018-09-18 17:19 被阅读35次

最近要在App中添加夜间模式,一般来说,夜间模式使用主题的方式实现,但因为App中历史遗留问题较多,更换主题的方式工作量比较大,所以就打算在App的每一个Activity中添加一层半透明的黑色遮罩来实现。

开启夜间模式时,在每一个Activity的Window中添加一个半透明View,并把View保存起来,关闭夜间模式时从Window中移除这个View,核心代码如下:

// 开启夜间模式
fun Activity.nightMode(): View {
    val nightViewParam = WindowManager.LayoutParams(
            WindowManager.LayoutParams.TYPE_APPLICATION,
            WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    /*or WindowManager.LayoutParams.FLAG_FULLSCREEN */ or WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
            PixelFormat.TRANSPARENT)
    nightViewParam.width = ViewGroup.LayoutParams.MATCH_PARENT
    nightViewParam.height = ViewGroup.LayoutParams.MATCH_PARENT
    nightViewParam.gravity = Gravity.CENTER
    val nightView = View(this)
    nightView.setBackgroundColor(0x99000000.toInt())
    windowManager.addView(nightView, nightViewParam)
    return nightView
}

// 关闭夜间模式
fun Activity.removeNightMode(view: View?) = view?.let { windowManager.removeViewImmediate(view) }

要在每一个Activity中都去做一次判断会比较繁琐,一种方式是通过在基类BaseActivity onStart中添加相关的代码判断当前是否是夜间模式,另一种方式是我在之前的文章Android判断程序回到前台并获取剪贴板数据中提到的在Application中注册ActivityLifecycleCallbacks的方式来处理。

// Application中
private WeakHashMap<Activity, View> nightModeHashMap = new WeakHashMap<>();

registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    }

    @Override
    public void onActivityStarted(Activity activity) {
        checkNightMode(activity);
    }

    @Override
    public void onActivityResumed(Activity activity) {
    }

    @Override
    public void onActivityPaused(Activity activity) {
    }

    @Override
    public void onActivityStopped(Activity activity) {
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        if (nightModeHashMap.containsKey(activity)) {
            nightModeHashMap.remove(activity);
        }
    }
});

public void checkNightMode(Activity activity) {
    if (activity == null) return;
    if (SharedPreferencesHelper.isNightMode()) {
        if (!nightModeHashMap.containsKey(activity))
            nightModeHashMap.put(activity, ActivityExtensionKt.nightMode(activity));
    } else {
        if (nightModeHashMap.containsKey(activity)) {
            ActivityExtensionKt.removeNightMode(activity, nightModeHashMap.get(activity));
            nightModeHashMap.remove(activity);
        }
    }
}

这种方式好处是不用修改Activity的代码,可以覆盖App中所有的页面,甚至是第三方SDK中的页面,并且后期要移除这个功能的时候也很容易。

相关文章

网友评论

  • 有点健忘:夜间模式不应该是字体颜色的变化吗,黑字白底 变成 白字黑底,不知道你这种效果啥样的,可以贴个图看看
  • deviche:不会影响点击事件吗
    fengmlo:不会。

本文标题:Android使用Window遮罩实现低成本夜间模式

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