Android技术知识Android开发经验谈Android开发

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

2018-09-18  本文已影响35人  fengmlo

最近要在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中的页面,并且后期要移除这个功能的时候也很容易。

上一篇下一篇

猜你喜欢

热点阅读