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