Android 中的状态栏(StatusBar)和导航栏(NavigationBar)

本文仅仅是将谷歌官方文档做一个翻译+注解,可能会稍微添加一些我自己理解的东西。想看原文的,戳这里 → Managing the System UI

管理系统 UI

先上一张图


这是一张 google play 的截图,上面用红色圈起来的就是 status bar,下面用绿色圈起来的,就是navigation bar

Android 将 StatusBar 和 NavigationBar 统称为 “SystemBar”。

一般来说,StatusBar 上用来显示一些软件通知、系统信息等。我们可以通过将其亮度调暗或者直接隐藏 StatusBar,以达到“帧·全屏”的效果,譬如播放视频、展示图片,如果显示 StatusBar 的话,会影像观影效果。

NavigationBar 就顾名思义了,提供导航,用于返回等操作。

根据软件的功能,合理的运用 SystemBar,以给用户良好的体验。

弱化 SystemBar

在 Android 4.0(API 14)之后,Android 提供了弱化 SystemBar 的方法,也就是说,在 4.0 之前的版本中,如果我们要弱化 SystemBar,需要借助其他方法,这个后面会说道。

将 SystemBar 弱化的好处在于,系统并不会中心调整其 UI 大小,只是相关图标会变化,会变得不再直接显示给用户,如下图:

注意看,弱化之后的 SystemBar 并没有直接隐藏,而是 StatusBar 隐藏了一些图标,只留下了电源和时间(事实上,假如其他 App 也有在 StatusBar 上显示,也会被隐藏),NavigationBar 变成了三个点,当用户触摸 SystemBar 的时候,才会显示出来。

怎么实现这样的效果呢?Android 提供了 SYSTEM_UI_FLAG_LOW_PROFILE 来弱化 StatusBar 和 NavigationBar,使用方法如下:

// This example uses decor view, but you can use any visible view.
View decorView = getActivity().getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE;
decorView.setSystemUiVisibility(uiOptions);

在上面的图片当中我们是通过触摸 SystemBar 来去除弱化效果的,当然也可以通过代码来去除:

decorView.setSystemUiVisibility(0);

API 中对于 SYSTEM_UI_FLAG_LOW_PROFILE 的描述为:设置该 flag,表示该 View 向系统请求进入“低调”模式,该模式用于“读书”、“游戏”、“播放视频”等应用,在该模式下,导航栏以及状态栏图标会变暗,以免用户分心。


隐藏状态栏

有的时候我们需要将 SystemBar 完全隐藏,以达到完全全屏的效果,不同的版本隐藏 SystemBar 的方法也不同。

Android 4.0 (API 14)及更低版本
在这些版本中,可以通过代码或者设置清单文件来隐藏。

  • 配置清单文件:
<application
    ...
    android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
    ...
</application>
  • 通过代码隐藏:
        if (Build.VERSION.SDK_INT < 16) {
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }

Android 4.1 (API 16)及更高版本
在 4.1 及之后的版本,我们依旧可以通过 setSystemUiVisibility 方法来隐藏,将其设置为 SYSTEM_UI_FLAG_FULLSCREEN

View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);

API 中对于 SYSTEM_UI_FLAG_FULLSCREEN 的描述为:表示该 View 请求进入正常的全屏模式,非关键的屏幕装饰(譬如状态栏)会被隐藏,其内容可以接管屏幕。

需要注意点是,我们设置了隐藏 StatusBar,当我们执行操作唤出 StatusBar 之后,那么该标签就会被清除,如果我们想要重新进入隐藏模式,需要重新设定,我们可以通过设定监听器来监听状态栏的显示状态,会在后面讲到。


沉浸式 StatusBar

有时候我们想要将界面全屏显示,但又想要显示 StatusBar 的内容,那就就用到了所谓的 “沉浸式”,其实也很容易实现,只需要将 StatusBar 设置为透明,然后将我们的布局全屏显示就好:

        // 通过 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 将布局设置为全屏显示
        View view = getWindow().getDecorView();
        int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
        view.setSystemUiVisibility(option);
        // StatusBar 设置为透明
        getWindow().setStatusBarColor(Color.TRANSPARENT);

官方文档当中说,最好是将该 flag 和 SYSTEM_UI_FLAG_LAYOUT_STABLE 搭配使用,SYSTEM_UI_FLAG_LAYOUT_STABLE 的作用是帮助应用维持一个稳定的布局(什么意思?没整明白,回头整明白了再补充吧)。


隐藏导航栏

隐藏导航栏和隐藏状态栏一样,都是通过 setSystemUiVisibility 方法设置一个 flag,只不过值换成了 SYSTEM_UI_FLAG_HIDE_NAVIGATION

设置了该 flag 之后,NavigationBar 会被隐藏,当点击屏幕时,会再次显示

沉浸式导航栏

和沉浸式状态栏一样,同样是两步:1.把布局设置为全屏显示;2.将导航栏设置为透明:

        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
        getWindow().setNavigationBarColor(Color.TRANSPARENT);

使用沉浸式全屏显示模式

在 Android 4.4(API 19)之后引入了一个新的 flag:SYSTEM_UI_FLAG_IMMERSIVE,官方文档说它可以让我们的应用进入真正的全屏模式,但是我觉得似乎毫无意义(几乎可以肯定是因为我能力太次认知有限了)。

之前不是说过了隐藏 StatusBar 和 NavigationBar 的方法了么,为什么又要引入这个呢?查询了一系列资料之后得到了解答,往下看。

首先 SYSTEM_UI_FLAG_IMMERSIVE flag 必须和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 以及 SYSTEM_UI_FLAG_FULLSCREEN 搭配使用,仅仅单独使用该标签是无效的,当它和另外两个 flag 搭配使用的时候,可以达到全屏的效果,当滑动屏幕的时候,另外两个标签会被消除,如果需要回到全屏,需要重新设置。看到这里,这个标签和之前的隐藏状态栏导航栏没啥区别嘛!对,我也这么觉得...哈哈

其实我觉得终点在与 SYSTEM_UI_FLAG_IMMERSIVE 的一个“子类”:SYSTEM_UI_FLAG_IMMERSIVE_STICKY,使用该该标签和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 以及 SYSTEM_UI_FLAG_FULLSCREEN 搭配使用之后,当我们滑动屏幕唤出状态栏或者导航栏之后,在经过一段时间之后,状态栏又会重新隐藏,无需我们再手动设置隐藏标签。因为这个“显示”只是暂时的,所以在显示的时候并不会出发监听器。


UI显示状态监听器

我们可以通过设置监听器来监听 SystemBar 的显示状态,和设置其他基础监听器一样,也没啥好说的 :

        getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                //do somethings
            }
        });

需要说明的是一下状态:

导航栏和状态栏都处于隐藏状态:6

导航栏处于隐藏状态:2

状态栏处于隐藏状态:4

状态栏和导航栏处于显示状态:0

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1