🔍
📢
Android全屏沉浸模式 - Full-screen Immersive Mode

Android全屏沉浸模式 - Full-screen Immersive Mode

🗨

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是否为沉浸模式的方法是view.getWindowSystemUiVisibility() == 5888,如果是非透明系统栏的模式下则为view.getWindowSystemUiVisibility() == 3840

这些可以自己写个demo用log打印出来就知道了。

复制代码
 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             if (Fullscreen) {
14                 //需要开启沉浸模式则把actionbar先隐藏掉,不然在Activity跳转时会闪出来。
15                 actionBar.hide();
16                 //进入沉浸模式
17                 SystemUI.hideSystemUI(view);
18                 //在根布局获得第一个控件,也就是最上层的layout。把内边距设为0
19                 vGroup.getChildAt(0).setPadding(0, 0, 0, 0);
20             } else if (view.getWindowSystemUiVisibility() == 5888){  //等于5888表示当前View是沉浸模式
21                 //当为否且当前view为沉浸模式时退出沉浸模式,显示actionbar
22                 actionBar.show();
23                 SystemUI.showSystemUI(view);
24                 //获得系统栏高度和actionbar高度,设置内边距。
25                 Rect frame = new Rect();
26                 view.getWindowVisibleDisplayFrame(frame);
27                 vGroup.getChildAt(0).setPadding(0, actionBar.getHeight() + frame.top, 0, 0);
28             }
29         }
30         super.onResume();
31     }
1 public static int getSystemVersion() { //这是获取系统版本的方法
2         int ver = android.os.Build.VERSION.SDK_INT;
3         return ver;
4     }

频道:Android