转自:
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; }