轉自:
Android狀態欄微技巧,帶你真正理解沉浸式模式
什么叫沉浸式?
根據百度百科上的定義,沉浸式就是要給用戶提供完全沉浸的體驗,使用戶有一種置身於虛擬世界之中的感覺。
那么對應到Android操作系統上面,怎樣才算是沉浸式體驗呢?這個可能在大多數情況下都是用不到的,不過在玩游戲或者看電影的時候就非常重要了。因為游戲或者影視類的應用都希望能讓用戶完全沉浸在其中,享受它們提供的娛樂內容,但如果這個時候在屏幕的上方還顯示一個系統狀態欄的話,可能就會讓用戶分分鍾產生跳戲的感覺
一個安卓應用程序的頁面上包含着許多系統元素
可以看到,有狀態欄、ActionBar、導航欄等。而打造沉浸式模式的用戶體驗,就是要將這些系統元素全部隱藏,只留下主體內容部分。
隱藏狀態欄和ActionBar的方式在4.1系統上下是不一樣的,因此不考慮4.1系統一下的兼容性,因為以前的系統沒有提供沉浸式體驗的支持
首先我們來實現全屏顯示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="fanggao.qf.immersivetest.MainActivity"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/a"/> </LinearLayout>
main:
// 另外,根據Android的設計建議,ActionBar是不應該獨立於狀態欄而單獨顯示的,因此狀態欄如果隱藏了,我們同時也需要調用ActionBar的hide()方法將ActionBar也進行隱藏。
注意:得到的actionBar必須是v7包向下兼容的,否則會空指針,找不到actionBar
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //得到當前界面的裝飾視圖 View decorView = getWindow().getDecorView(); // SYSTEM_UI_FLAG_FULLSCREEN表示全屏的意思,也就是會將狀態欄隱藏 //設置系統UI元素的可見性 decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN); //隱藏標題欄 ActionBar actionBar = getSupportActionBar(); actionBar.hide(); }
效果如下:
這樣看上去就有點沉浸式效果的模樣了。
雖說這才是正統的沉浸式含義,但如果我們想要實現餓了么那樣的狀態欄效果,而不是直接把整個系統狀態欄給隱藏掉,那么又該如何實現呢?
其實也很簡單,只需要借助另外一種UI Flag就可以了
首先需要注意,餓了么這樣的效果是只有5.0及以上系統才支持,因此需要if判斷,只有系統版本大於或等於5.0的時候才會執行下面的代碼。
注意下面的參數與上面的不同
上面: View.SYSTEM_UI_FLAG_FULLSCREEN
下面:View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//得到當前界面的裝飾視圖 if(Build.VERSION.SDK_INT >= 21) { View decorView = getWindow().getDecorView(); //讓應用主題內容占用系統狀態欄的空間,注意:下面兩個參數必須一起使用 stable 牢固的 int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LAYOUT_STABLE; decorView.setSystemUiVisibility(option); //設置狀態欄顏色為透明 getWindow().setStatusBarColor(Color.TRANSPARENT); } //隱藏標題欄 ActionBar actionBar = getSupportActionBar(); actionBar.hide();
效果:
餓了么頁面效果就出來了
但如果我們需要實現沉浸式的效果,光隱藏狀態欄是不夠的,還需要隱藏導航欄
修改代碼如下:
//得到當前界面的裝飾視圖 if(Build.VERSION.SDK_INT >= 21) { View decorView = getWindow().getDecorView(); //設置讓應用主題內容占據狀態欄和導航欄 int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_LAYOUT_STABLE; decorView.setSystemUiVisibility(option); //設置狀態欄和導航欄顏色為透明 getWindow().setStatusBarColor(Color.TRANSPARENT); getWindow().setNavigationBarColor(Color.TRANSPARENT); } //隱藏標題欄 ActionBar actionBar = getSupportActionBar(); actionBar.hide(); }
手機沒有導航欄不做演示,但大致跟上圖一樣,只是下方有導航欄的幾個按鈕(背景已被設置為透明了)
但這並不是真正的沉浸式效果,我們在做沉浸式效果之前,必須考慮是否真正需要這個效果,因為只有向游戲或者視頻這種需要給用戶帶來良好用戶體驗的應用程序才需要這種效果
需要注意的是,只有在Android 4.4及以上系統才支持沉浸式模式,因此這里也是加入了if判斷。
代碼如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//設置成全屏模式
// setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//豎屏
//設置屏幕為橫屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.activity_main);
}
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); //判斷是否有焦點 if(hasFocus && Build.VERSION.SDK_INT >= 19){ 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 |View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |View.SYSTEM_UI_FLAG_FULLSCREEN |View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ); } }
效果如下:
界面默認情況下是全屏的,狀態欄和導航欄都不會顯示。而當我們需要用到狀態欄或導航欄時,只需要在屏幕頂部向下拉,或者在屏幕右側向左拉,狀態欄和導航欄就會顯示出來,此時界面上任何元素的顯示或大小都不會受影響。過一段時間后如果沒有任何操作,狀態欄和導航欄又會自動隱藏起來,重新回到全屏狀態。
這就是最標准的沉浸式模式。
如何獲取狀態欄的高度
/*獲取狀態欄的高度*/ private int getStatusBarHeight() { Class<?> c = null; Object obj = null; Field field = null; int x = 0, statusBarHeight = 0; try { c = Class.forName("com.android.internal.R$dimen"); obj = c.newInstance(); field = c.getField("status_bar_height"); x = Integer.parseInt(field.get(obj).toString()); statusBarHeight = getResources().getDimensionPixelSize(x); } catch (Exception e1) { e1.printStackTrace(); } return statusBarHeight; }