管理状态栏和导航栏

系统栏(system bar)是用来显示通知、设备状态和导航的屏幕区域。一般来说,系统栏(system bar)包括状态栏(status bar)和导航栏(navigation bar),它们与应用程序同时显示在屏幕上。而相册、视频等沉浸式的应用可以淡化系统栏来创造一个更加专注的体验环境,甚至是完全隐藏系统栏。

下面来介绍如何在不同的版本中淡化和隐藏系统栏,营造一个沉浸式的用户体验,同时还可以快速操作系统栏。

注:本文参考Android Develop Training - Manager the System UI。

一、淡化系统栏(System Bar)

由于Android的早期版本没有提供API来淡化系统栏,下面只介绍如何在Android 4.0及更高的版本中淡化系统栏。

(1).淡化状态栏和导航栏
状态栏和导航栏在被淡化后,依旧会占据屏幕空间,只是其中的图标和操作按钮变成了灰白色的小圆点。
使用SYSTEM_UI_FLAG_LOW_PROFILE标识,可以达到淡化状态栏和导航栏的效果。代码如下。
// 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);

一旦用户操作了状态栏和导航栏,这个标识就会被清除,使状态栏和导航栏重新显现。标识被清除后,如果需要再次淡化状态栏和导航栏,必须重新设定这个标识。


管理状态栏和导航栏_第1张图片      管理状态栏和导航栏_第2张图片

左图为默认状态,右图为淡化之后的状态。


(2).显示状态栏和导航栏
在状态栏和导航栏添加了SYSTEM_UI_FLAG_LOW_PROFILE标识被淡化后,如果需要再次显示出来,可以使用如下方法清除标识。
View decorView = getActivity().getWindow().getDecorView();
// Calling setSystemUiVisibility() with a value of 0 clears
// all flags.
decorView.setSystemUiVisibility(0);

二、隐藏状态栏(Status Bar)

隐藏状态栏可以让应用得到更多的展示空间,从而提供一个更加沉浸式的用户体验。下面介绍如何在不同的Android版本中隐藏状态栏。

左图为显示状态栏的效果,右图为状态栏隐藏后的显示效果。

管理状态栏和导航栏_第3张图片     管理状态栏和导航栏_第4张图片

(1).在4.0及以下版本中隐藏状态栏
在Android 4.0及以下版本中,可以通过设置WindowManager来隐藏状态栏。可以使用java代码动态设置,也可以在manifest文件中设置Activity的主题。

    ...

通过设置主题来隐藏状态栏的优势:
1.易于维护,因为这种方式不像动态设置那样容易出错。
2.界面切换更流畅,因为在初始化Activity之前,系统已经得到了渲染UI的信息。

另外也可以动态隐藏状态栏。示例代码如下。
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // If the Android version is lower than Jellybean, use this call to hide
        // the status bar.
        if (Build.VERSION.SDK_INT < 16) {
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
        setContentView(R.layout.activity_main);
    }
    ...
}

当设置了WindowManager之后(无论是通过主题还是动态设置),效果会一直存在直到手动清除。

(2).在4.1及以上版本中隐藏状态栏
在Android 4.1及以上版本中,可以使用setSystemUiVisibility()方法来隐藏状态栏。setSystemUiVisibility()在View层面设置UI的标识,然后这些设置被整合到Window层面。代码如下。
View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
// Remember that you should never show the action bar if the
// status bar is hidden, so hide that too if necessary.
ActionBar actionBar = getActionBar();
actionBar.hide();

注意:
1.一旦设定的UI标识被清除(比如跳转到另一个Activity),如果还需要隐藏状态栏就必须再次设定。
2.在不同的地方设置UI标识是有区别的。如果在Activity的onCreate()方法中隐藏状态栏,当用户按下home键系统栏就会重新显示。当用户重新打开Activity时,onCreate()方法不会被调用,所以状态栏还是可见的。如果想在不同的Activity之间切换时,可见性保持不变,需要在onResume()与onWindowFocusChaned()里设定UI标识。
3.setSystemUiVisibility()只在被调用的View显示时才会生效。
4.当从当前视图转到别的页面时,setSystemUiVisibility()设置的标识会被清除。

(3).让内容显示在状态栏之后
在Android 4.1及以上版本,可以将应用的内容显示在状态栏之后,这样当状态栏显示与隐藏时,内容区域的大小就不会发生变化。要达到这个效果,需要用到SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN这个标识。同时,也可以使用SYSTEM_UI_FLAG_LAYOUT_STABLE这个标志来帮助应用维持一个稳定的布局。

当使用这种方法时,你就需要来确保应用中特定区域不会被系统栏覆盖(比如地图应用中一些自带的操作区域)。如果被覆盖了,应用可能就会无法使用。在大多数的情况下,可以在布局文件中添加android:fitsSystemWindows属性并设置为true。它会调整父ViewGroup使它留出特定区域给系统栏,对于大多数应用这种方法就足够了。

在一些情况下,可能需要修改默认的padding大小来获取合适的布局。为了控制内容区域的布局相对系统栏(系统栏占据了一个叫做content insets的区域)的位置,可以重写fitSystemWindows(Rect insets)方法。当窗口的内容嵌入区域发生变化时,fitSystemWindows()方法会被view层级调用,让View做出相应的调整适应。重写这个方法你就可以按你的意愿处理嵌入区域与应用的布局。

三、隐藏导航栏(Navigation Bar)

Android在4.0版本之后,引入了对导航栏隐藏的操作。

管理状态栏和导航栏_第5张图片


(1).在4.0及以上版本中隐藏导航栏
在Android 4.0及以上版本中,可以使用SYSTEM_UI_FLAG_HIDE_NAVIGATION标识来隐藏导航栏。下面这段代码同时隐藏了导航栏和状态栏。
View decorView = 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.使用该方法时,触摸屏幕的任何区域都会使导航栏(和状态栏)重新显示。用户的交互会使SYSTEM_UI_FLAG_HIDE_NAVIGATION标识被清除。
2.一旦该标识被清除,如果要再次隐藏导航栏,需要重新设置标识。
3.在不同的地方设置UI标识是有区别的。如果在Activity的onCreate()方法中隐藏系统栏,当用户按下home键系统栏就会重新显示。当用户重新打开Activity时,onCreate()方法不会被调用,所以状态栏还是可见的。如果想在不同的Activity之间切换时,可见性保持不变,需要在onResume()与onWindowFocusChaned()里设定UI标识。
4.setSystemUiVisibility()只在被调用的View显示时才会生效。
5.当从当前视图转到别的页面时,setSystemUiVisibility()设置的标识会被清除。

(2).让内容显示在导航栏之后
在Android 4.1及以上版本中,可以将应用的内容显示在导航栏的后面,这样当导航栏显示与隐藏时,内容区域的大小就不会发生变化。要达到这个效果,需要用到SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION这个标识。同时,也可以使用SYSTEM_UI_FLAG_LAYOUT_STABLE这个标志来帮助应用维持一个稳定的布局。

当使用这种方法的时候,就需要你来确保应用中特定区域不会被系统栏覆盖。

四、使用沉浸式模式(Immersive Full-Screen Mode)

Adnroid 4.4为setSystemUiVisibility()方法引入了一个新的标识SYSTEM_UI_FLAG_IMMERSIVE,它可以让应用进入真正的全屏模式。当该标识与SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN一起使用时,导航栏和状态栏就会隐藏,让应用可以接受屏幕上任何区域的触摸事件。

当沉浸式全屏模式启用的时候,你的Activity会继续接受各类的触摸事件。用户可以通过在边缘区域向内滑动来让系统栏重新显示,这个操作清空了SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN两个标识,因此系统栏重新变得可见。如果标识被设置了,这个操作同时也触发了View.OnSystemUiVisibilityChangeListener监听器。然而, 如果需要让系统栏在一段时间后自动隐藏的话,应该使用SYSTEM_UI_FLAG_IMMERSIVE_STICKY标签。注意,带有'sticky'的标识不会触发任何监听器,因为在这种模式下显示的系统栏只有短暂的停留时间。
管理状态栏和导航栏_第6张图片

在上图中:
图1.非沉浸模式。该模式展示了应用程序在进入沉浸模式之前的状态,同时也是在设置了SYSTEM_UI_FLAG_IMMERSIVE标识后用户滑动重写显示出系统栏的状态。当用户滑动后,SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN就会被清除,系统栏就会重新显示并保持可见。 
注意,最好让所有的UI控件的变化与系统栏的显示隐藏保持同步,这样可以减少屏幕显示所处的状态,同时提供了更无缝平滑的用户体验。因此所有的UI控件跟随系统栏一同显示。一旦应用进入了沉浸模式,相应的UI控件也跟随着系统栏一同隐藏。为了确保UI的可见性与系统栏保持一致,可以添加View.OnSystemUiVisibilityChangeListener来监听系统栏的显示隐藏变化。
图2.提示气泡。第一次进入沉浸模式时,系统将会显示一个提示气泡,提示用户如何再让系统栏显示出来。
图3.沉浸模式。在该模式下,系统栏和其他UI操作都被隐藏。可以通过设置IMMERSIVE和IMMERSIVE_STICKY标识来进入这个状态。
图4.STICKY标识。这是在设置了SYSTEM_UI_FLAG_IMMERSIVE_STICKY标签时的状态,用户会向内滑动以展示系统栏。半透明的系统栏会临时的进行显示,一段时间后自动隐藏。滑动操作并不会清空任何标识,也不会触发系统栏可见性的监听器,因为暂时显示的导航栏并不被认为是一种可见性状态的变化。

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

(1).选择一种沉浸方式
SYSTEM_UI_FLAG_IMMERSIVE和SYSTEM_UI_FLAG_IMMERSIVE_STICKY标识都提供了沉浸式的体验,下面通过一些示例讲解这两种标识该如何选择。
1.如果是在图书、新闻或杂志阅读器应用中,可以将IMMERSIVE标识与SYSTEM_UI_FLAG_FULLSCREEN和SYSTEM_UI_FLAG_HIDE_NAVIGATION一起使用。因为用户可能会经常操作Action Bar和一些UI控件,又不希望在翻页时有其他的东西进行干扰,IMMERSIVE在是个很好的选择。
2.如果需要打造一款真正的沉浸式应用,而且希望屏幕边缘的区域也可以与用户进行交互,并且用户也不会经常访问系统栏,这个时候可以将IMMERSIVE_STICKY和SYSTEM_UI_FLAG_FULLSCREEN、SYSTEM_UI_FLAG_HIDE_NAVIGATION两个标识一起使用。比如一款游戏或者绘图应用就很合适。
3.如果是一个视频播放器应用,需要少量的用户交互操作,简单的使用SYSTEM_UI_FLAG_FULLSCREEN与SYSTEM_UI_FLAG_HIDE_NAVIGATION就足够了,不需要使用IMMERSIVE标签。

(2).使用IMMERSIVE沉浸模式
当使用SYSTEM_UI_FLAG_IMMERSIVE标识时,它是基于其他设置过的标识SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN来隐藏系统栏的。当用户触摸向内滑动,系统栏重新显示并保持可见。

用其他的UI标识(如SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION和SYSTEM_UI_FLAG_LAYOUT_STABLE)来防止系统栏隐藏时内容区域大小发生变化是一种很好的方法,同时也需要确保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);
}

(3).使用IMMERSIVE_STICKY沉浸模式

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

管理状态栏和导航栏_第7张图片

下面的示例代码,在窗口获取焦点时,使用IMMERSIVE_STICKY沉浸模式。根上面的方法一样,只是将IMMERSIVE修改为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);
    }
}

五、监听系统栏的显示和隐藏变化
对View设置View.OnSystemUiVisibilityChangeListener监听器,可以监听系统栏的显示和隐藏变化。
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.
        }
    }
});

保持系统栏和应用程序的UI同步是一种很好的方式,比如当状态栏显示或隐藏的时候进行ActionBar的显示和隐藏等。

你可能感兴趣的:(Android基础)