上次写过一篇解决沉浸式状态栏问题的文章,不过当时仅仅是为了解决两个问题,没有过多理解过沉浸式,以至于每次发开需要沉浸式都需要网上搜索半天,然后拷贝代码过来,修改修改就得了,今天正好静下心来好好思考了一下沉浸式。

页面做成沉浸式的思路有两个:

第一.就是直接修改状态栏的颜色,需要什么颜色就将状态栏的颜色改成什么颜色,就这么简单,没了。纯白色沉浸式设置代码如下:

/**

* 设置沉浸式状态栏

*/

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

《瀑布》影評|劇情風格轉來轉去, 結局來個當頭棒喝!
十二星座谁是牛郎星(牛郎星和织女星分别属于什么星座)