天天看點

沉浸式體驗四:全屏模式全屏模式

導航

  • 全屏模式
    • 全屏模式
      • 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 是不會被觸發的。