上次写过一篇解决沉浸式状态栏问题的文章,不过当时仅仅是为了解决两个问题,没有过多理解过沉浸式,以至于每次发开需要沉浸式都需要网上搜索半天,然后拷贝代码过来,修改修改就得了,今天正好静下心来好好思考了一下沉浸式。
页面做成沉浸式的思路有两个:
第一.就是直接修改状态栏的颜色,需要什么颜色就将状态栏的颜色改成什么颜色,就这么简单,没了。纯白色沉浸式设置代码如下:
/**
* 设置沉浸式状态栏
*/
public static void immersiveNotificationBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//字体颜色改为黑色,非白色沉浸式状态栏不需要设置
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
immersiveNotificationBar(activity, 255);
}
/**
* 设置沉浸式状态栏
*/
public static void immersiveNotificationBar(Activity activity, int alpha) {
String brand = Build.BRAND;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//解决华为手机等状态栏上面有一个蒙层问题
try {
Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView");
Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor");
field.setAccessible(true);
field.setInt(window.getDecorView(), Color.TRANSPARENT); //改为透明
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
if ("vivo".equalsIgnoreCase(brand) || "OPPO".equals(brand)) {//oppo和vivo手机状态栏最好不要显示为纯白色,官方未给出改变字体颜色为黑色方法
window.setStatusBarColor(Color.argb(alpha, 208, 208, 208));
} else {
window.setStatusBarColor(Color.argb(alpha, 255, 255, 255));
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
int count = decorView.getChildCount();
if (count > 0 && null != decorView.getChildAt(count - 1)) {
decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(Color.WHITE, 30));
} else {
View statusView = createStatusBarView(activity, Color.WHITE, 30);
decorView.addView(statusView);
}
setRootView(activity);
}
}
private static View createStatusBarView(Activity activity, @ColorInt int color, int alpha) {
View statusBarView = new View(activity);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStarusBarHeight(activity));
statusBarView.setLayoutParams(params);
statusBarView.setBackgroundColor(calculateStatusColor(color, alpha));
return statusBarView;
}
private static void setRootView(Activity activity) {
ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
rootView.setFitsSystemWindows(true);
rootView.setClipToPadding(true);
}
private static int calculateStatusColor(@ColorInt int color, int alpha) {
float a = 1 - alpha / 255f;
int red = color >> 16 & 0xff;
int green = color >> 8 & 0xff;
int blue = color & 0xff;
red = (int) (red * a + 0.5);
green = (int) (green * a + 0.5);
blue = (int) (blue * a + 0.5);
return 0xff << 24 | red << 16 | green << 8 | blue;
}
public static int getStarusBarHeight(Context context) {
int statusBarHeight1 = -1;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
statusBarHeight1 = context.getResources().getDimensionPixelSize(resourceId);
}
return statusBarHeight1;
}
代码复制过去就可以了,然后将setStatusBarColor里的颜色值改成自己的就可了,很简单。
第二种方法,就是将状态栏的颜色改为透明,然后页面设置为全屏显示,自己页面顶部预留一个view来当做状态栏。这个呢,灵活性高,可控性也好,相对于第一种来说适用范围更广,可以说就是我自己想让状态栏显示什么就显示什么,当然了仔细想想其实这是一种假象。具体过程分为三个步骤:
1)页面设置为全屏且显示状态栏,状态栏为透明
/**
* 通过设置全屏,设置状态栏透明
*
* @param activity
*/
private void fullScreen(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
Window window = activity.getWindow();
View decorView = window.getDecorView();
//两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
decorView.setSystemUiVisibility(option);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
//导航栏颜色也可以正常设置
// window.setNavigationBarColor(Color.TRANSPARENT);
} else {
Window window = activity.getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
attributes.flags |= flagTranslucentStatus;
// attributes.flags |= flagTranslucentNavigation;
window.setAttributes(attributes);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//解决华为手机等状态栏上面有一个蒙层问题
try {
Class decorViewClazz = Class.forName("com.android.internal.policy.DecorView");
Field field = decorViewClazz.getDeclaredField("mSemiTransparentStatusBarColor");
field.setAccessible(true);
field.setInt(getWindow().getDecorView(), Color.TRANSPARENT); //改为透明
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
2)设置布局中的顶部view高度为状态栏高度(或者自己想着顶部直接弄成顶天的图片也可以)
3)设置顶部view的颜色,随意修改达到沉浸式,甚至可以添加图片都无所谓
好了,沉浸式状态栏问题就这样基本解决了,再回头想想,真的没什么。不过最让人头疼的应该是国产系统的适配问题解决,沉浸式中最难的应该就是属于白色沉浸式问题,状态栏颜色变成深色问题。下面我们来解决魅族手机状态栏字体颜色问题。
问题如下:
Activity+四个Fragment,Fragment切换时切换状态栏颜色没问题,但是在其中一个Fragment中跳转另一个Activity,然后再回来的时候设置黑色状态栏的那个Fragment就失效了,请问是怎么回事?每次点击切换Fragment的时候都有设置状态栏颜色。
很不幸我也遇到了这个问题,我们分析分析为什么?魅族手机牛逼的地方在于他会自动读取状态栏下面view的颜色值,然后根据读取到的颜色值来自动设置字体的颜色,尼玛,这就完全不可控了啊!!!!我觉得应该不止魅族系统这样,奥,对了,使用魅族官网的设置状态栏字体颜色的代码也照样没卵用。那么我们怎么办?欺骗系统,我们可以欺骗系统,怎么欺骗?就是当系统读取状态栏后面view的时候,我们提前手动设置view的颜色,等着读取完了我们再改成我们想要的颜色,这不就解决了!还是以需要状态栏字体为黑色为例(沉浸式状态栏设置方式为上面第二种方法):
第一步:直接操作我们要显示的沉浸式view或者在view上面再覆盖一层也可以,我们就以上面再覆盖一层view为例吧,xml中view的颜色要设置为白色。
重写window获取焦点的方法,当页面获取到焦点时我们将覆盖的view设置为透明颜色
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
if (null == mView) {//mView就是状态栏或者上面覆盖的一层
mView = findViewById(R.id.status_view);
mView.post(new Runnable() {//为了解决初次进来状态栏字体颜色为白色
@Override
public void run() {
mView.setBackgroundColor(Color.TRANSPARENT);
}
});
} else {
mView.setBackgroundColor(Color.TRANSPARENT);
}
}
}
第二步:就是当页面彻底不可见的时候我们再次将view的北京颜色设置为白色,当页面再次可见时扔会执行上面代码设置为透明
@Override
protected void onStop() {
super.onStop();
if (null != mView) {
mView.setBackgroundColor(Color.WHITE);
}
}
这里需要说明为什么是在onstop中而不是onpause方法中设置,在onpause中设置会让用户看见白色的状态栏,所以用在onstop中设置。
最后贴一张图(魅蓝note6)手机上的效果:
最后将github源码地址贴一下,欢迎star: https://github.com/zhq217217/chenjinshi_statusbar