状态栏(StatusBar)与导航栏(NavigationBar)沉浸式

状态栏(StatusBar)与导航栏(NavigationBar)沉浸式

前言:ActionBar与ToolBar

原理

  • 导航栏

导航栏我们在做应用层开发的时候一般很少去设置或者额外的操作,采用的是系统默认的白色。
1:在5.0之前我们无法设置导航栏的颜色,5.0之后我们可以设置导航栏的颜色
2:当我们为Window窗口设置FLAG_TRANSLUCENT_NAVIGATION,在5.0之前表现最下边会有阴影效果,表现不是很好。5.0之后不会有阴影效果
3:当设置了FLAG_TRANSLUCENT_NAVIGATION,我们铺满布局的下方会与导航栏重合。

public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;

        /**
         * Window flag: request a translucent navigation bar with minimal system-provided
         * background protection.
         *
         * 

This flag can be controlled in your theme through the * {@link android.R.attr#windowTranslucentNavigation} attribute; this attribute * is automatically set for you in the standard translucent decor themes * such as * {@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor}, * {@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor}, * {@link android.R.style#Theme_DeviceDefault_NoActionBar_TranslucentDecor}, and * {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor}.

* *

When this flag is enabled for a window, it automatically sets * the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.

*/ public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;

实现方式以下两种

代码

window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

theme 中设置

 true

android4.4表现效果图如下:

状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第1张图片
image.png

android5.0表现效果图如下:


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第2张图片
image.png
  • 状态栏

记得自己在5.0之前开发app,大部分状况关于状态栏我们一般全是采用系统默认,不会做任何处理,一般是黑色的。当时认为这也很好看的,也没这个沉浸式概念。当然在Android4.4之前,我们的应用没法改变手机的状态栏颜色,当我们打开应用时在屏幕的顶部有一条黑色的状态栏,google在Android4.4以后提供了设置沉浸式状态栏的方法,在5.0之前其实际的效果就是透明的状态栏,然后在状态栏的位置用我们自己的控件视图作显示,其颜色通常为应用的actionbar或者自己定义的标题栏的颜色,或者是将应用的整体的一张图片也占据到状态栏中。
在5.0之后我们也采用了浸式状态栏,6.0之前,这时候有的ui小姐姐效果图会出现白色的状态栏,导航栏的文字 、图标信息全部变为深黑。要知道在6.0之前除了特定的小米 、魅族手机可以实现外,当时也不知道如何做了。

  • 解释:设置状态栏透明,并且变为全屏模式。上面的解释已经说得很清楚了,当window的这个属性有效的时候,会自动设置 system ui visibility的标志SYSTEM_UI_FLAG_LAYOUT_STABLE和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 。

根据开发体验沉浸式可以分成三个阶段: Android关于沉浸式状态栏总结

  • Android4.4(API 19) - Android 5.0(API 21):
    这个阶段可以实现沉浸式,但是表现的效果还不是很好,实现方式为: 通过 FLAG_TRANSLUCENT_STATUS 设置状态栏为透明并且为全屏模式,然后通过添加一个与StatusBar 一样大小的View,将View 的 background 设置为我们想要的颜色,从而来实现沉浸式。
  • Android 5.0(API 21)以上版本:
    在Android 5.0的时候,加入了一个重要的属性和方法 android:statusBarColor (对应方法为 setStatusBarColor),通过这个方法我们就可以轻松实现沉浸式。也就是说,从Android5.0开始,系统才真正的支持沉浸式。
  • Android 6.0(API 23)以上版本:
    其实Android6.0以上的实现方式和Android 5.0 +是一样,为什么要将它归为一个单独重要的阶段呢?是因为从Android 6.0(API 23)开始,我们可以改状态栏的绘制模式,可以显示白色或浅黑色的内容和图标(除了魅族手机,魅族自家有做源码更改,6.0以下就能实现)

1:Android4.4(API 19) - Android 5.0(API 21)实现沉浸式的方式

Android 4.4 WindowManager中新增了一个重要的属性 :FLAG_TRANSLUCENT_STATUS

/**
         * Window flag: request a translucent status bar with minimal system-provided
         * background protection.
         *
         * 

This flag can be controlled in your theme through the * {@link android.R.attr#windowTranslucentStatus} attribute; this attribute * is automatically set for you in the standard translucent decor themes * such as * {@link android.R.style#Theme_Holo_NoActionBar_TranslucentDecor}, * {@link android.R.style#Theme_Holo_Light_NoActionBar_TranslucentDecor}, * {@link android.R.style#Theme_DeviceDefault_NoActionBar_TranslucentDecor}, and * {@link android.R.style#Theme_DeviceDefault_Light_NoActionBar_TranslucentDecor}.

When this flag is enabled for a window, it automatically sets * the system UI visibility flags {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.

*/ public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
  • 解释:设置状态栏透明,并且变为全屏模式。上面的解释已经说得很清楚了,当window的这个属性有效的时候,会自动设置 system ui visibility的标志SYSTEM_UI_FLAG_LAYOUT_STABLE和SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 。

有两种方式实现这个属性:

可以在代码中设置,如下:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

当然也可以在theme 中设置属性windowTranslucentStatus,如下:

true

效果如下:

状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第3张图片
Android 4.4系统上的效果图

这里有两个问题
1:标题栏和状态栏重叠了,相当于整个布局上移了StatusBar 的高度
2:顶部会有暗色阴影

问题1的解决,标题栏的上方添加一个大小和StatusBar大小一样的View,View 的BackgroundColor 为标题栏一样的颜色,这个View起到一个占位的作用。这个时候,标题栏就会下移StatusBar的高度,回到正常的位置。

代码如下:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Window window = getWindow();
        //android 5.0以上
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(ContextCompat.getColor(this,R.color.colorPrimary));
        } else {
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            ViewGroup systemContent = findViewById(android.R.id.content);
            View statusBarView = new View(this);
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    getStatusBarHeight());
            statusBarView.setBackgroundColor(ContextCompat.getColor(this,R.color.colorPrimary));
            systemContent.getChildAt(0).setFitsSystemWindows(true);
            systemContent.addView(statusBarView, 0, lp);
        }
    }
private int getStatusBarHeight() {
        Class c;
        Object obj;
        Field field;
        int x, statusBarHeight = 0;
        try {
            c = Class.forName("com.android.internal.R$dimen");
            obj = c.newInstance();
            field = c.getField("status_bar_height");
            x = Integer.parseInt(field.get(obj).toString());
            statusBarHeight =getResources().getDimensionPixelSize(x);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return statusBarHeight;
    }
状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第4张图片
处理后的效果.png

问题2的解决,在小于5.0之前没有找到去掉阴影的方法。5.0之后,系统不会有这样的效果了。
如果是一张图片延伸到状态栏的话,直接设置FLAG_TRANSLUCENT_STATUS就可以了

android 4.4表现效果


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第5张图片
image.png

android 5.0表现效果


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第6张图片
image.png

小结:Android4.4上实现沉浸式状态栏的套路是:为window添加FLAG_TRANSLUCENT_STATUS Flag,然后添加一个和status bar 一样大小的View 站位,从而让让标题栏不会与status bar 重叠。而图片延伸到状态栏只需要设置FLAG_TRANSLUCENT_STATUS就OK。导航栏的的操作同样与状态栏类似,只不过在开发过程中遇到的情况较少,一般系统默认。

2.2 Android 5.0(API 21)以上实现沉浸式的方式
Android 5.0 是一个里程碑式的版本,从Android 5.0开始,Google 推出了全新的设计规范 Material Design,并且原生控件就可以实现一些炫酷的UI动效。在5.0中默认就支持我们所谓的沉浸式,新建一个5.0的项目。


说明:Theme.AppCompat.Light.NoActionBar,在5.0之后我们不会使用ActionBa,取而代之的是ToolBar。


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第7张图片
image.png

各个颜色的指向可以参考
AndroidStudio之Theme、colorPrimary、colorPrimaryDark、colorAccent详解

android5.0之后,google 加入了一个比较重要的方法 setStatusBarColor (对应属性:android:statusBarColor),通过这个方法,可以很轻松地实现沉浸式状态栏,对于导航栏是setNavigationBarColor(对应属性:android:navigationBarColor)。具体实现如下
getWindow().setStatusBarColor(Color.RED);
getWindow().setNavigationBarColor(Color.RED);

效果如下


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第8张图片
image.png

图片延伸到状态栏

从这个版本开始,google 加入了一个比较重要的方法 setStatusBarColor (对应属性:android:statusBarColor),通过这个方法,可以很轻松地实现沉浸式状态栏。方法如下:

在window类中

    /**
     * Sets the color of the status bar to {@code color}.
     *
     * For this to take effect,
     * the window must be drawing the system bar backgrounds with
     * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
     * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.
     *
     * If {@code color} is not opaque, consider setting
     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
     * 

* The transitionName for the view background will be "android:status:background". *

*/ public abstract void setStatusBarColor(@ColorInt int color);

想要这个方法有效果,必须设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,而且FLAG_TRANSLUCENT_STATUS不可使用 (Android 4.4才用这个)

解释:设置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,表明会Window负责系统bar的background 绘制,绘制透明背景的系统bar(状态栏和导航栏),然后用getStatusBarColor()和getNavigationBarColor()的颜色填充相应的区域。这就是Android 5.0 以上实现沉浸式导航栏的原理。

实现方式以下两种
1:代码实现

//android 5.0以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    window.addFlags(WindowManager.LayoutParams.
    FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    //注意要清除 FLAG_TRANSLUCENT_STATUS flag
    getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    window.setStatusBarColor(ContextCompat.getColor(this,R.color.colorPrimary));
}

2 Theme中配置

false
true
@color/colorPrimary

效果如下:


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第9张图片
image.png

图片延伸到状态栏

效果图如下:
在Android 5.0 使图片延伸到状态栏,只需设置windowTranslucentStatus,将 statusBarColor 设置为透明即可:


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第10张图片
image.png

前提知识点:
1:状态栏和导航栏窗口是系统级窗口而Activity对应的时应用窗口,它们属于不同的窗口层级
2: 状态栏和导航栏系统级窗口是在App应用窗口之上,Activity应用窗口虽然有整个屏幕的大小,
但是可显示内容的区域得除去其上叠加的不透明的窗口区域(正常状态下也就是状态栏下方导航栏上方区域,
当然是可以设置叠加显示的)
Android窗口管理服务WindowManagerService计算Activity窗口大小的过程分析
https://blog.csdn.net/luoshengyang/article/details/8479101/

window.getDecorView().setSystemUiVisibility(int visibility)这个方法参数表示的状态有如下

1:View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  Activity在导航栏上部全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态栏遮住。

2:View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  Activity在状态栏下部全屏显示,但导航栏不会被隐藏覆盖,导航栏依然可见,Activity下端布局部分会被导航栏遮住。

3:View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  防止系统栏(包含导航栏与状态栏)隐藏时内容区域大小发生变化

4:View.SYSTEM_UI_FLAG_VISIBLE
  显示状态栏,Activity不全屏显示(恢复到有状态的正常情况)。

5:View.INVISIBLE
  隐藏状态栏,同时Activity会伸展全屏显示。

6:View.SYSTEM_UI_LAYOUT_FLAGS
  效果同1一样

7:View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
  隐藏虚拟按键(导航栏)。

8:View.SYSTEM_UI_FLAG_LOW_PROFILE
  状态栏显示处于低能显示状态(low profile模式),状态栏上一些图标显示会被隐藏。

window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
Flag表明这个窗口负责绘制系统状态栏标题栏的背景。如果设置,系统bar(包含状态栏与导航栏)绘制成透明背景,
在这个窗口相应的地方会填充{@link Window#getStatusBarColor()}
和{@link Window#getNavigationBarColor()}对应的颜色。

通过代码实现如下:

getWindow().requestFeature(Window.FEATURE_NO_TITLE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    Window window = getWindow();
    //activity视图只在状态栏下部与导航栏上部区域显示
    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
            | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    //Activity在导航栏上部全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态栏遮住。
    //Activity在状态栏下部全屏显示,但导航栏不会被隐藏覆盖,导航栏依然可见,Activity下端布局部分会被导航栏遮住。
    window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
    /*
     * 表明这个窗口负责绘制系统状态栏标题栏的背景。如果设置,系统bar绘制成透明背景,在这个窗口相应的地方会填充
     * {@link Window#getStatusBarColor()}和{@link Window#getNavigationBarColor()}对应的颜色*/
    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    window.setStatusBarColor(Color.TRANSPARENT);
    window.setNavigationBarColor(Color.TRANSPARENT);
}
setContentView(R.layout.activity_main);

效果图如下:


状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第11张图片
image.png

2.3 Android 6.0 + 实现状态栏字色和图标浅黑色

使用沉浸式的时候会遇到一个问题,那就是Android 系统状态栏的字色和图标颜色为白色,当我的主题色或者图片接近白色或者为浅色的时候,状态栏上的内容就看不清了。 ,这个问题在Android 6.0的时候得到了解决。Android 6.0 新添加了一个属性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

解释:为setSystemUiVisibility(int)方法添加的Flag,请求status bar 绘制模式,它可以兼容亮色背景的status bar 。要在设置了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDSflag ,同时清除了FLAG_TRANSLUCENT_STATUSflag 才会生效。

实现代码

//如果亮色,设置状态栏文字为黑色
if (isLightColor(color)) {
    //暗色字体
    getWindow().getDecorView().setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}else {
    //白色字体
    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            |View.SYSTEM_UI_FLAG_VISIBLE);
}

Theme主题中使用

false
true
@android:color/holo_red_light

true
状态栏(StatusBar)与导航栏(NavigationBar)沉浸式_第12张图片
image.png

推荐一个好的库
ImmersionBar

你可能感兴趣的:(状态栏(StatusBar)与导航栏(NavigationBar)沉浸式)