天天看点

沉浸式体验四:全屏模式全屏模式

导航

  • 全屏模式
    • 全屏模式
      • Lean Back
      • Immersive
      • Immersive Sticky
    • 全屏模式实现

全屏模式

有的内容是非常适合采用全屏模式去呈现的,比如视频、游戏、相册、读书等等,此文介绍如何使用全屏模式去加深用户对内容的关注度同时预防用户意外退出应用。

沉浸式体验四:全屏模式全屏模式

不要为了获取最大的屏幕空间就轻易的使用全屏模式,因为在不确定用户会有多频繁的去检查通知或者做一些突然的搜索等操作,就采用全屏模式的话会让用户不能方便的去进行系统栏操作。只有当通过全屏模式能够获取到的收益远远超过得到一些额外的屏幕空间才推荐去使用(比如预防用户在游戏中突然退出或者向用户传递有价值的图片、视频、阅读沉浸式体验)。

全屏模式

Android 提供了三个模式去实现应用全屏:Lean Back,Immersive,Immersive Sticky。在三种模式下,系统栏都会隐藏并且应用Activity仍然会收到所有的触摸事件,不过用户在这三种模式下恢复系统栏显示的操作方式就有所不同了。

Lean Back

Lean Back 模式是当处于全屏模式下,用户与屏幕的交互事件比较少的情况,比如看电影。

当用户想显示系统栏的时候,仅需要轻轻点击屏幕的任意区域。

为了实现 Lean Back 模式,需要调用 setSystemUiVisibility() 并传递 SYSTEM_UI_FLAG_FULLSCREEN 和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 标志。

当系统栏重新显示的时候,可以通过 响应系统UI变化 监听去做相应的应用UI变更。

Immersive

Immersive 模式用于全屏模式下,用户与屏幕交互频繁的情况,比如玩游戏,查看相册图片,或者阅读书籍。

当想重新显示系统栏的时候,需要用户从系统栏隐藏的边缘向里滑动,通过如此更加刻意的手势需求,减少了意外的点击和滑动对用户app使用造成的中断影响。

为了实现 Immersive 模式,需要调用 setSystemUiVisibility() 并且在 SYSTEM_UI_FLAG_FULLSCREEN 和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 标志基础上结合传递 SYSTEM_UI_FLAG_IMMERSIVE。

如果你的应用有自己的一套当用户沉浸式体验的时候需要隐藏起来的控制,那就最好通过 Responding to UI Visibility Changes 保持与系统栏的同步显示与隐藏。

Immersive Sticky

在普通 Immersive 模式中,用户的一次从边缘的滑动都会导致系统重新显示系统栏,然而当应用真的包含需要从边缘滑动的基本操作时,比如一款需要很多滑动手势的游戏或者绘图工具,我们就应该采用 Immersive Sticky 模式。

当处于 Immersive Sticky 模式时,用户从边缘的一次滑动同样会使系统栏以半透明的方式重新显示出来,但该手势仍然会传递到应用并产生相应的响应。

比如用户在使用绘图工具时,需要画一条从边缘而来的直线,此次操作会显示出系统栏同时从画布的边缘绘制一条直线,系统栏会在几秒后或用户点击非系统栏区域后消失。

为了实现 Immersive Sticky 模式,需要调用 setSystemUiVisibility() 并且在 SYSTEM_UI_FLAG_FULLSCREEN 和 SYSTEM_UI_FLAG_HIDE_NAVIGATION 标志基础上结合传递 SYSTEM_UI_FLAG_IMMERSIVE_STICKY。

然而在 Immersive Sticky 模式下,应用就不能再接收到 响应系统UI变化 的回调,所以如果想同时有 Immersive Sticky 的自动隐藏系统栏,又同时想监听系统 UI 的回调,可以采用 Immersive 模式同时通过 Handler.postDelayed() 或相似的方式去实现几秒后再次隐藏系统栏。

全屏模式实现

不管采用哪种全屏模式,都需要调用 setSystemUiVisibility() 并且传递 SYSTEM_UI_FLAG_HIDE_NAVIGATION, SYSTEM_UI_FLAG_FULLSCREEN,或者两个一起。同时可以包含 SYSTEM_UI_FLAG_IMMERSIVE(普通Immersive模式)或者 SYSTEM_UI_FLAG_IMMERSIVE_STICKY(Immersive Sticky模式),或者两个都不要(Lean Back模式)。

包含其他标志(比如SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,SYSTEM_UI_FLAG_LAYOUT_STABLE)去防止布局大小因系统栏显示隐藏导致的改变是一个不错的实践,同时要保证标题栏和其他操作与系统栏的统一性-同时显示或隐藏。

实现代码如下:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus) {
        hideSystemUI();
    }
}

private void hideSystemUI() {
    // Enables regular immersive mode.
    // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
    // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
    View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_IMMERSIVE
            // Set the content to appear under the system bars so that the
            // content doesn't resize when the system bars hide and show.
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            // Hide the nav bar and status bar
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_FULLSCREEN);
}

// Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
    View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
           

或许你还想通过以下方式去提供更好的用户体验:

  • 提供无缝过渡在各个状态下,保持应用的控制 UI 与系统栏的一致性。一旦应用进入 Immersive 模式,应用的任何控制 UI 都应该同时被隐藏起来,并且能够同系统栏一起显示出来。为此,需要实现 View.OnSystemUiVisibilityChangeListener 去接收回调进行监听,正如 响应系统UI变化 所描述的一样。
  • 实现 onWindowFocusChanged() 方法,一旦获取到窗口焦点,应用或许应该重新隐藏系统栏,而当窗口失去焦点,比如当出现弹窗 dialog 或者 popup 的时候,就应该取消之前的任何延迟隐藏系统栏的操作。
  • 实现 GestureDetector 中的 onSingleTapUp(MotionEvent) 方法去向提供用户手动点击内容区域隐藏显示系统栏的途径。普通的点击事件并不是最好的解决方案,因为就算用户手指在内容区域的滑动都会触发该事件(假设点击事件的监听对象占据了整个屏幕)。
注意:当使用 SYSTEM_UI_FLAG_IMMERSIVE_STICKY 标志时,边缘滑动会使系统栏以半透明的方式显示出来,但是不会有任何的标志被清除,同时 View.OnSystemUiVisibilityChangeListener 是不会被触发的。