Android4.4的發布帶來了新的特性-沉浸模式(Full-screen Immersive Mode),開啟后應用占據全屏,虛擬按鈕和系統欄隱藏,提高屏幕的利用率和沖擊力。
那么怎樣為我們的應用加入這個模式呢?先查看下Google的官方文檔,里面有完整的示例代碼。
1 // This snippet hides the system bars. 2 private void hideSystemUI() { 3 // Set the IMMERSIVE flag. 4 // Set the content to appear under the system bars so that the content 5 // doesn't resize when the system bars hide and show. 6 //開啟全屏模式 7 mDecorView.setSystemUiVisibility( 8 View.SYSTEM_UI_FLAG_LAYOUT_STABLE 9 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 10 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 11 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar 12 | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar 13 | View.SYSTEM_UI_FLAG_IMMERSIVE); 14 } 15 16 // This snippet shows the system bars. It does this by removing all the flags 17 // except for the ones that make the content appear under the system bars. 18 //取消全屏模式 19 private void showSystemUI() { 20 mDecorView.setSystemUiVisibility( 21 View.SYSTEM_UI_FLAG_LAYOUT_STABLE 22 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 23 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 24 }
進入全屏后從屏幕上下放往里滑可重新喚出系統欄和虛擬按鈕,但是喚出后系統欄會蓋住一小部分內容,這個時候要給根layout設置一個高度為系統欄高度的Padding才能解決,后面會講到。
而且要再進入全屏模式還要再點擊一次按鈕。所以我比較推薦下面的模式,喚出的是透明的系統欄和虛擬按鈕,短暫的時間后系統欄和虛擬按鈕會自動隱藏。
只需要把View.SYSTEM_UI_FLAG_IMMERSIVE改為View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY。
1 @Override 2 public void onWindowFocusChanged(boolean hasFocus) { 3 super.onWindowFocusChanged(hasFocus); 4 if (hasFocus) { 5 decorView.setSystemUiVisibility( 6 View.SYSTEM_UI_FLAG_LAYOUT_STABLE 7 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 8 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 9 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 10 | View.SYSTEM_UI_FLAG_FULLSCREEN 11 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);} 12 }
如果你的應用有ActionBar的話也會被隱藏掉,退出全屏模式后ActionBar會重新出現,但是和系統欄一樣會覆蓋在你的布局上。
這是開啟前: 這是開啟后: 關閉全屏后按鈕被標題欄覆蓋掉了
這時候就需要用到ActionBar的覆蓋模式了(Overlaying the Action Bar),具體設置請看Google的文檔。
如果你用的是support v7兼容包的ActionBar可能會設置不了樣式,請看我之前的一篇隨筆來解決這個問題。
要解決被覆蓋的問題需要動態設置根布局的內邊距,請看下面的設置:
1 public class MainActivity extends Activity implements OnClickListener { 2 private RelativeLayout rlLayout; 3 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_main); 8 //設置ACtionBar 9 ActionBar actionBar = getActionBar(); 10 actionBar.setDisplayHomeAsUpEnabled(true); 11 actionBar.setHomeButtonEnabled(true); 12 13 rlLayout = (RelativeLayout) findViewById(R.id.rlayout); 14 Button mButtonOn = (Button) findViewById(R.id.button_on); 15 Button mButtonOff = (Button) findViewById(R.id.button_off); 16 mButtonOn.setOnClickListener(this); 17 mButtonOff.setOnClickListener(this); 18 } 19 20 public void onClick(View v) { 21 //獲得根視圖 22 View view = getWindow().getDecorView(); 23 switch (v.getId()) { 24 case R.id.button_on: 25 //進入沉浸模式 26 hideSystemUI(view); 27 //把內邊距設為0 28 rlLayout.setPadding(0, 0, 0, 0); 29 break; 30 case R.id.button_off: 31 //退出沉浸模式 32 showSystemUI(view); 33 //獲得系統欄高度 34 Rect frame = new Rect(); 35 view.getWindowVisibleDisplayFrame(frame); 36 //需要設置的內邊距為ActionBar高度和系統欄高度相加 37 int paddingTop = getActionBar().getHeight() + frame.top; 38 rlLayout.setPadding(0, paddingTop, 0, 0); 39 break; 40 } 41 42 } 43 44 @Override 45 public boolean onCreateOptionsMenu(Menu menu) { 46 getMenuInflater().inflate(R.menu.main, menu); 47 return true; 48 } 49 50 @SuppressLint("NewApi") 51 public static void hideSystemUI(View view) { 52 view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE 53 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 54 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 55 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 56 | View.SYSTEM_UI_FLAG_FULLSCREEN 57 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 58 } 59 60 @SuppressLint("NewApi") 61 public static void showSystemUI(View view) { 62 view.setSystemUiVisibility( 63 View.SYSTEM_UI_FLAG_LAYOUT_STABLE 64 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 65 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 66 } 67 }
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:id="@+id/rlayout" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:paddingTop="?android:attr/actionBarSize" 7 tools:context=".MainActivity" >
如果我需要把一個應用里的所有activity都設為沉浸模式呢?只需要重寫activity的onResume()方法,然后把這個activity設為父類,讓所有的activity繼承它就可以了。
因為每創建一個新的activity都要檢測是否開啟全屏模式,而如果在后一個activity里設為全屏后返回上一個activity時也要檢測是否變成全屏模式。
下面是我的應用里onResume()的設置,因為我的應用要兼容android2.1所以Actionbar用的是support v7包,獲取Actionbar是用getSupportActionBar();
如果你的應用需要在進入沉浸模式后通知其他UI改變的話可以加入一個監聽器View.OnSystemUiVisibilityChangeListener()。
檢測當前activity是否為沉浸模式的方法是
1 int status = View.SYSTEM_UI_FLAG_LAYOUT_STABLE 2 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 4 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 5 | View.SYSTEM_UI_FLAG_FULLSCREEN 6 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 7 view.getSystemUiVisibility() == status;
如果在后面的activity里退出了沉浸模式。那么返回前一個activity的時候,前一個activity要檢查下是否要退出沉浸模式。在onResume()里面檢查就可以。
1 protected void onResume() { 2 // 判斷是否是android4.4 3 if (SystemInfo.getSystemVersion() > 18) { 4 SharedPreferences sPreferences = getSharedPreferences("AppBrightness", 0); 5 // 讀取存在SharedPreferences里的設置 6 boolean Fullscreen = sPreferences.getBoolean("Fullscreen", false); 7 ActionBar actionBar = getSupportActionBar(); 8 // 獲得根視圖 9 View view = getWindow().getDecorView(); 10 // 獲得根布局 11 ViewGroup vGroup = (ViewGroup) (view.findViewById(android.R.id.content)); 12 // 用於判斷應用是否已經退出沉浸模式了。 13 int status = View.SYSTEM_UI_FLAG_LAYOUT_STABLE 14 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 15 | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 16 | View.SYSTEM_UI_FLAG_VISIBLE 17 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 18 // 判斷是否要開啟沉浸模式 19 if (Fullscreen) { 20 // 需要開啟沉浸模式則把actionbar先隱藏掉,不然在Activity跳轉時會閃出來。 21 actionBar.hide(); 22 // 進入沉浸模式 23 SystemUI.hideSystemUI(view); 24 // 在根布局獲得第一個控件,也就是最上層的layout。把內邊距設為0 25 vGroup.getChildAt(0).setPadding(0, 0, 0, 0); 26 } else if (view.getSystemUiVisibility() == status){ 27 // 如果應用已經退出沉浸模式,但是這個activity還是在沉浸模式內,則退出沉浸模式。 28 actionBar.show(); 29 SystemUI.showSystemUI(view); 30 // 獲得系統欄高度和actionbar高度,設置內邊距。 31 Rect frame = new Rect(); 32 view.getWindowVisibleDisplayFrame(frame); 33 vGroup.getChildAt(0).setPadding(0, actionBar.getHeight() + frame.top, 0, 0); 34 } 35 } 36 super.onResume(); 37 }
1 public static int getSystemVersion() { //這是獲取系統版本的方法 2 int ver = android.os.Build.VERSION.SDK_INT; 3 return ver; 4 }