管理System windows(status bar和navigation bar)

96
ForeverCy
2016.09.25 17:45* 字数 5335

概述

通常来说,System bars(包含status bar和navigation bar,如下图所示, 1代表status bar,2代表navigation bar)会和你的应用同时显示在屏幕上。应用为了可以沉浸式的显示内容,例如播放电影和图片的效果,可以通过暂时淡化System bars图标来实现减少分散用户注意力的体验,或者通过暂时隐藏System bars来实现完全沉浸式的的体验。

下面介绍在不同版本Android系统中如何通过淡化或者隐藏System bars的方式来营造沉浸式的用户体验,同时仍保留轻松访问System bars。

1 淡化System bars(Dimming the System Bars)
本部分介绍怎么在Android4.0(API级别14)和更高的版本中淡化System bars。 在早期版本的Android系统中Android没有提供内置的淡化System bars的方法。
淡化System bars的方式并不会改变UI的大小,只是status bar和navigation bar的相关图标会被弱化,比如navigation bar的几个虚拟键会弱化成很细微的小点。一旦你再次触摸 status bar和navigation bar 的所在区域,他们就会再次显示。这种方式的好处是status bar和navigation bar仍然显示在屏幕上,但是它们的细节变模糊了,从而在不牺牲轻松访问System bars的前提下创建了一个沉浸式的用户体验。

代码实现如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
    dimSystemBars();   
}

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

只要用户触摸了status bar和navigation bar 的所在区域,SYSTEM_UI_FLAG_LOW_PROFILE标志就会被清除,使得status bar和navigation bar淡化效果消失。如果你的应用想要再次淡化status bar和navigation bar,你就需要重新如上设置。

下面这张图展示了在gallery应用中显示一张图片时, navigation bar被淡化的效果(注意status bar没有显示并不是淡化了,而是gallery应用直接隐藏了它),请注意,navigation bar (图像的右侧)上有淡淡的灰白色的小圆点表示导航控件,这就是navigation bar 被淡化后的效果。

下图展示了System bars完全显示的效果:

上面提到,当System bars处于淡化的情况时,一旦你点击 status bar和navigation bar 的所在区域,SYSTEM_UI_FLAG_LOW_PROFILE标志就会被清除,使得status bar和navigation bar淡化效果消失。你也可以通过如下代码手动清除SYSTEM_UI_FLAG_LOW_PROFILE标志:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
    cancelDimSystemBars();
}

private void cancelDimSystemBars() {
    View decorView = getWindow().getDecorView();
    // Calling setSystemUiVisibility() with a value of 0 clears
    // all flags.
    decorView.setSystemUiVisibility(0);
}

2 隐藏System bars(Hiding the System bars)

1> 隐藏Status Bar(Hiding the Status Bar)
本小节介绍在不同的Android版本中如何隐藏状态栏。隐藏状态栏让App的content区域——Activity中setContentView()中传入的就是content——使用更多的显示空间,从而提供更加沉浸式的用户体验。

下图展示了Status Bar可见时的app:


下图展示了Status Bar隐藏时的app。请注意,Action Bar也被隐藏了,我们认为当Status Bar和Action Bar应该被同时隐藏。


在android4.0(API 14)及以下的版本中,你可以通过设置WindowManager
的flag来隐藏status bar。有两种方式来设置WindowManager
的flag,一是在java代码中动态设置,二是在manifest文件中设置activity的theme。如果你的status bar想要一直隐藏的话,在manifest中设置activity的theme是最好的方式,例如:

<application
    ...
    android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
    ...
</application>

在manifest中设置activity theme的方式的优点如下:
<1> 更容易维护,相对于在java代码中动态设置的方式更不容易出错。
<2> UI过渡更加的流畅,因为系统在实例化Activity之前就已经获得了渲染UI所需要的消息。

另外,可以通过在java代码中动态设置WindowManager的flag。这种方式可以更加灵活地隐藏和显示状态栏:

private void hideStatusBar() {
    // If the Android version is lower than Jellybean, use this call to hide
    // the status bar.
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
}

private void cancelHideStatusBar() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
}

在Android 4.1 (API 16)或者更高版本中,你可以使用setSystemUiVisibility()来隐藏Status Bar,使用setSystemUiVisibility()设置UI flag比设置WindowManager flag的方式拥有更多的控制选项,隐藏Status Bar的示例代码如下:

private void hideStatusBar() {
    // If the Android version is lower than Jellybean, use this call to hide
    // the status bar.
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
    } else {
        View decorView = getActivity().getWindow().getDecorView();
        // Hide the status bar.
        int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);
    }
}

以下几点需要注意:
<1> 一旦UI flag被清空(比如跳转到另外的Activity),如果你想要再一次隐藏Status Bar,那么你需要重写设置UI flag。为了对Status Bar的隐藏和显示做出及时的响应,可以通过监听System bars可见性的改变:

View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
        (new View.OnSystemUiVisibilityChangeListener() {
    @Override
    public void onSystemUiVisibilityChange(int visibility) {
        // Note that system bars will only be "visible" if none of the
        // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
            // TODO: The system bars are visible. Make any desired
            // adjustments to your UI, such as showing the action bar or
            // other navigational controls.
        } else {
            // TODO: The system bars are NOT visible. Make any desired
            // adjustments to your UI, such as hiding the action bar or
            // other navigational controls.
        }
    }
});

<2> 在不同的地方设置Ui flag是有区别的,如果你是在onCreate中设置UI flag隐藏System bars,当用户点击home键,System bars将重新出现,用户重新回到这个activity的时候,onCreate是不会被调用的,所以System bars仍然是可见的。因此如果你想在activity切换回来的时候仍然保持System bars的状态,最好是在onResume()或者onWindowFocusChanged()方法中设置UI flag。
<3> 只有当调用setSystemUiVisibility()的view是可见的setSystemUiVisibility()才会起作用。
<4> 界面的切换会导致setSystemUiVisibility()的设置被清空

让App的content区域——Activity中setContentView()中传入的就是content——显示在Status Bar后面
在 android4.1(API 16)以及更高的版本,可以让App的content区域出现在Status Bar的后面,Status Bar不再影响到实际内容的空间摆放(以前App的content总是在Status Bar下面),因此在Status Bar显示或者隐藏时,App的content区域的大小就不会发生变化。要达到这种效果只需使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN标志(flag)。同时,你也有可能需要SYSTEM_UI_FLAG_LAYOUT_STABLE这个标志来帮助你的应用维持一个稳定的布局(这句话不理解)。

因为App的content区域在Status Bar之后,这个时候你就需要确保app中需要操作的区域不会被Status Bar挡住,不过大多数情况下在布局文件中添加android:fitsSystemWindows属性(值为true)可以解决Status Bar挡住App的content区域的问题,因为该设置可以调整ViewGroup的padding,为系统控件预留一定的区域。对于绝大多数应用来说,这样做已经足够了。

为什么我们要让App的content区域出现在Status Bar的后面:既然无论如何都需要预留空间给Status Bar ,那为什么我们还需要将App的content区域显示在Status Bar的后面呢?这一般是为了满足这种需求:
在一个显示图片的列表(如RecycleView)中,当列表滚动的时候,我们希望Status Bar背后是有内容在滚动的,但是当列表滑到了顶端,我又希望列表是没有被Status Bar挡住的。

在一些情况下,你可能需要修改默认的padding大小来获取合适的布局。为了控制App的content区域的布局相对System bars(它占据了一个叫做“内容嵌入”content insets的区域)的位置,你可以重写fitSystemWindows(Rect insets)方法。当窗口的content insets区域发生变化时,fitSystemWindows()方法会被view hierarchy调用,从而让View做出相应的调整适应。

fitSystemWindows方法中的参数insets的值就是System bars占有空间的大小

2> 隐藏Navigation Bar(Hiding the Navigation Bar)
本小节介绍如何隐藏Navigation Bar,这是在Android 4.0时(API级别14)推出的。

虽然本小节关注隐藏Navigation Bar,但是在实际的开发中,你最好同时隐藏Navigation Bar和Status Bar,隐藏Navigation Bar与Status Bar(在保证易于再次访问的情况下)使App的content区域占据了整个显示空间,从而提供了一个更加沉浸式的用户体验。

通过SYSTEM_UI_FLAG_HIDE_NAVIGATION flag来隐藏Navigation Bar,同时隐藏Navigation Bar和Status Bar的代码如下:

private void hideNavigationBar() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        View decorView = getActivity().getWindow().getDecorView();
        // Hide both the navigation bar and the status bar.
        // SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
        // a general rule, you should design your app to hide the status bar whenever you
        // hide the navigation bar.
        int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN;
        decorView.setSystemUiVisibility(uiOptions);
    }
}

以下几点需要注意:
<1> 使用这个方法时,触摸屏幕的任何地方都会使Navigation Bar和Status Bar重新显示。用户的交互使这个标志SYSTEM_UI_FLAG_HIDE_NAVIGATION被清除。

<2> 一旦标志SYSTEM_UI_FLAG_HIDE_NAVIGATION被清空,如果你想要再一次隐藏Navigation Bar和Status Bar,那么你需要重置标志SYSTEM_UI_FLAG_HIDE_NAVIGATION。为了对Navigation Bar和Status Bar的隐藏和显示做出及时的响应,可以通过监听System bars可见性的改变,方法与1>中相同。

<3> 在不同的地方设置Ui flag是有区别的,如果你是在onCreate中设置UI flag隐藏System bars,当用户点击home键,System bars将重新出现,用户重新回到这个activity的时候,onCreate是不会被调用的,所以System bars仍然是可见的。因此如果你想在activity切换回来的时候仍然保持System bars的状态,最好是在onResume()或者onWindowFocusChanged()方法中设置UI flag。

<4> 只有当调用setSystemUiVisibility()的view是可见的setSystemUiVisibility()才会起作用。

<5> 界面的切换会导致setSystemUiVisibility()的设置被清空

让App的content区域——Activity中setContentView()中传入的就是content——显示在Navigation Bar后面
在 android4.1(API 16)以及更高的版本,可以让App的content区域出现在Navigation Bar的后面,Navigation Bar不再影响到实际内容的空间摆放(以前App的content总是在Navigation Bar上面),因此在Navigation Bar显示或者隐藏时,App的content区域的大小就不会发生变化。要达到这种效果只需使用SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION标志(flag)。同时,你也有可能需要SYSTEM_UI_FLAG_LAYOUT_STABLE这个标志来帮助你的应用维持一个稳定的布局(这句话不理解)。

当你使用这种方法的时候,这个时候你就需要确保app中需要操作的区域不会被System bars遮盖。更详细的说明1>中关于这一点的讨论。

3 全屏沉浸模式(Using Immersive Full-Screen Mode)
在android4.4及以上版本中为setSystemUiVisibility()方法
引入了一个新的flag:SYSTEM_UI_FLAG_IMMERSIVE,它可以使你的app实现真正意义上的全屏体验。当SYSTEM_UI_FLAG_IMMERSIVE、SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN三个flag一起使用的时候,可以隐藏Navigation Bar和Status Bar,同时让你的app可以捕捉到用户的所有触摸屏事件。

当沉浸式全屏模式启用的时候,你的activity会继续接受各类的触摸事件。用户可以通过在Navigation Bar和Status Bar原来区域的边缘向内滑动让Navigation Bar和Status Bar重新显示。这个操作清空了SYSTEM_UI_FLAG_HIDE_NAVIGATION(和SYSTEM_UI_FLAG_FULLSCREEN,如果有的话)两个标志,因此System bars重新变得可见。如果设置了的话,这个操作同时也触发了View.OnSystemUiVisibilityChangeListener。然而, 如果你想让System bars在一段时间后自动隐藏的话,你应该使用SYSTEM_UI_FLAG_IMMERSIVE_STICKY
标签。请注意,'sticky'版本的flag不会触发任何的监听器,因为在这个模式下展示的System bars是处于暂时的状态。
下图展示了各种不同的“沉浸式”状态


非沉浸模式 —— 展示了应用进入沉浸模式之前的状态。也展示了设置IMMERSIVE标签后用户滑动展示系统栏的状态。用户滑动后,SYSTEM_UI_FLAG_HIDE_NAVIGATION
和SYSTEM_UI_FLAG_FULLSCREEN就会被清除,系统栏就会重新显示并保持可见。请注意,最好的方式就是让所有的UI控件与系统栏的显示隐藏保持同步,这样可以减少屏幕显示所处的状态,同时提供了更无缝平滑的用户体验。因此所有的UI控件跟随系统栏一同显示。一旦应用进入了沉浸模式,UI控件也跟随着系统栏一同隐藏。为了确保UI的可见性与系统栏保持一致,我们需要一个监听器View.OnSystemUiVisibilityChangeListener来监听系统栏的变化。这在1>中将已经详细讲解。

提示气泡——第一次进入沉浸模式时,系统将会显示一个提示气泡,提示用户如何再让系统栏显示出来。请注意,如果为了测试你想强制显示提示气泡,你可以先将应用设为沉浸模式,然后按下电源键进入锁屏模式,并在5秒中之后打开屏幕。

沉浸模式—— 这张图展示了隐藏了系统栏和其他UI控件的状态。你可以设置IMMERSIVE或者IMMERSIVE_STICKY来进入这个状态。

粘性标签——这就是你设置了IMMERSIVE_STICKY标签时的UI状态,用户会向内滑动以展示系统栏。半透明的系统栏会临时的进行显示,一段时间后自动隐藏。滑动的操作并不会清空任何标签,也不会触发系统UI可见性的监听器,因为暂时显示的导航栏并不被认为是一种可见的状态。

注意,immersive类的标签只有在与SYSTEM_UI_FLAG_HIDE_NAVIGATION,SYSTEM_UI_FLAG_FULLSCREEN中一个或两个一起使用的时候才会生效。你可以只使用其中的一个,但是一般情况下你需要同时隐藏状态栏和导航栏以达到沉浸的效果。

如何确定使用哪种沉浸模式
SYSTEM_UI_FLAG_IMMERSIVE与SYSTEM_UI_FLAG_IMMERSIVE_STICKY都提供了沉浸式的体验,但是在上面的描述中,他们是不一样的,下面讲解一下什么时候该用哪一种标签。
如果你在写一款图书浏览器、新闻杂志阅读器,请将IMMERSIVE标签与SYSTEM_UI_FLAG_FULLSCREEN,SYSTEM_UI_FLAG_HIDE_NAVIGATION
一起使用。因为用户可能会经常访问Action Bar和一些UI控件,又不希望在翻页的时候有其他的东西进行干扰。IMMERSIVE在该种情况下就是个很好的选择。

如果你在打造一款真正的沉浸式应用,而且你希望屏幕边缘的区域也可以与用户进行交互,并且他们也不会经常访问系统UI。这个时候就要将IMMERSIVE_STICKY和SYSTEM_UI_FLAG_FULLSCREEN
SYSTEM_UI_FLAG_HIDE_NAVIGATION两个标签一起使用。比如做一款游戏或者绘图应用就很合适。

如果你在打造一款视频播放器,并且需要少量的用户交互操作。你可能就需要之前版本的一些方法了(从Android 4.0开始)。对于这种应用,简单的使用SYSTEM_UI_FLAG_FULLSCREEN与SYSTEM_UI_FLAG_HIDE_NAVIGATION就足够了,不需要使用immersive标签。

使用非STICKY的沉浸模式

当你使用SYSTEM_UI_FLAG_IMMERSIVE
标签的时候,它是基于其他设置过的标签(SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN)来隐藏System bars的。当用户向内滑动,系统栏重新显示并保持可见。用其他的UI标签(如SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION和SYSTEM_UI_FLAG_LAYOUT_STABLE)来防止System bars隐藏时内容区域大小发生变化是一种很不错的方法。你也需要确保Action Bar和其他系统UI控件同时进行隐藏。下面这段代码展示了如何在不改变内容区域大小的情况下,隐藏与显示状态栏和导航栏。

// This snippet hides the system bars.
private void hideSystemUI() {
    // Set the IMMERSIVE flag.
    // Set the content to appear under the system bars so that the content
    // doesn't resize when the system bars hide and show.
    mDecorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
            | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
            | View.SYSTEM_UI_FLAG_IMMERSIVE);
}

// This snippet shows the system bars. It does this by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
    mDecorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}

你可能同时也希望在如下的几种情况下使用IMMERSIVE标签来提供更好的用户体验:

<1> 注册一个监听器来监听System bars的变化。
<2> 实现onWindowFocusChanged()函数。如果窗口获取了焦点,你可能需要对系统栏进行隐藏。如果窗口失去了焦点,比如说弹出了一个对话框或菜单,你可能需要取消那些将要在Handler.postDelayed()或其他地方的隐藏操作。
<3> 实现一个GestureDetector,它监听了onSingleTapUp(MotionEvent)事件。可以使用户点击内容区域来切换系统栏的显示状态。单纯的点击监听可能不是最好的解决方案,因为当用户在屏幕上拖动手指的时候(假设点击的内容占据了整个屏幕),这个事件也会被触发。

使用STICKY的沉浸模式

当使用了SYSTEM_UI_FLAG_IMMERSIVE_STICKY标签的时候,向内滑动的操作会让System bars临时显示,并处于半透明的状态。此时没有标签会被清除,系统UI可见性监听器也不会被触发。如果用户没有进行操作,系统栏会在一段时间内自动隐藏。
图2展示了当使用IMMERSIVE_STICKY标签时,半透明的系统栏展示与又隐藏的状态。


下面是一段实现代码。一旦窗口获取了焦点,只要简单的设置IMMERSIVE_STICKY与上面讨论过的其他标签即可。

@Override
public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        decorView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                | View.SYSTEM_UI_FLAG_FULLSCREEN
                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);}
}

上面关于System bars的淡化、隐藏、沉浸式都是翻译的google文档


上面详细讲解了通过System bars的淡化、隐藏、沉浸式来实现沉浸式的效果,下面我们来看看通过System bars的透明化来实现更加沉浸式的效果。

4 透明化System bars
从 3.0 (honeycomb) 开始,Navigation Bar采用虚拟键,一直都占据一块不小的空间,对很多人来说,整个屏幕无法充利用,是一件相当痛苦的事情。也因此,有些人会刻意去挑选仍维持着实体键设计的手机。
而 Google 似乎也意识到这个状况,从 4.4 (KitKat) 提供了开发者一个新的作法,让最上方的状态栏 (Status Bar) 以及最下方的导航栏 (Navigation Bar) 可以被透明化,并让 APP 的内容可以往上下延伸,使整个画面的可被利用度大幅提升。

实现方式有两种,一种是Java代码动态设置,一种是设置Activity的theme,实现代码如下所示:

1. Java代码动态设置:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    //透明状态栏
    //getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    //透明导航栏
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
    //Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
    getWindow().setStatusBarColor(getResources().getColor(android.R.color.transparent));
} else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    //透明状态栏
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    //透明导航栏
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}

设置Activity的theme:
2. 在values、values-v19、values-v21的style.xml都设置一个 Translucent System Bar 风格的Theme

values/style.xml:
<style name="ImageTranslucentTheme" parent="AppTheme">
    <!--在Android 4.4之前的版本上运行,直接跟随系统主题-->
</style>

values-v19/style.xml:
<style name="ImageTranslucentTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
</style>

values-v21/style.xml:
<style name="ImageTranslucentTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="android:windowTranslucentStatus">false</item>
    <item name="android:windowTranslucentNavigation">true</item>
    <!--Android 5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色-->
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>

无论使用上面的那一种方式,都会存在一个问题,app的content区域——Activity中setContentView()中传入的就是content——就会在System bars后面显示,这时app中需要操作的区域就有可能被System bars挡住,通过fitsSystemWindows就可以解决这个问题,下面就着重讲一下fitsSystemWindows。

5 fitsSystemWindows的作用

大部分情况下,都不会在System windows下面显示内容,但是在实现沉浸式的效果时会导致在System windows下面显示内容,因此需要确保可交互控件(比如按钮)不要显示在System windows下面。android:fitsSystemWindows=“true” 默认行为就是通过在 View 上设置和System windows一样高度的边框(padding )来确保你的content部分——Activity中setContentView()中传入的就是content——不会与System windows重叠,因此android:fitsSystemWindows="true"的默认行为正好解决上面的情况。

以下是需要注意的地方:
1> fitsSystemWindows
fitsSystemWindows 按照深度优先的方式起作用的,因此如果一个 ViewGroup 使用了 inset (系统窗口的尺寸)则会导致其他与其相关的 View 受到影响。
2> Insets
始终相对于全屏幕
——Insets是相对于屏幕的,它决定着应用的Window的边界与屏幕边界的距离。因为Insets的生成在View layout之前就已经完成了,所以系统对于View长什么样一无所知。
3> 其它padding将通通被覆盖。需要注意,如果你对一个View设置了android:fitsSystemWindows="true",那么你对该View设置的其他padding将通通无效。

在绝大多数情况下,默认情况就已经够用了。比如一个全屏的视屏播放器。如果你不想被System Bars遮住的话,那么在ViewGroup上设置fitsSystemWindows="true"即可。

或者,也许你希望你的RecyclerView能够在透明的navigation bar 下面滚动。那么只需将android:fitsSystemWindows="true" android:clipToPadding="false"同时使用即可, 滚动的内容会绘制在navigation bar下面,同时当滚动到最下面的时候,最后一个item下面依旧会有padding,使其可以滚到navigation bar上方(而不是在navigation bar下面滚不上来!)。

译者注:clipToPadding是ViewGroup的属性。这个属性定义了是否允许ViewGroup在padding中绘制,该值默认为true,即不允许。

小知识点总结