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 }