为应用加上Android4.4新特性的全屏模式-沉浸模式(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是否为沉浸模式的方法是

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     }
posted @ 2014-01-08 00:48  黑暗中的一盏明灯  阅读(17497)  评论(8编辑  收藏  举报