Android4.4之后谷歌提供了沉浸式全屏体验,在沉浸式全屏模式下,状态栏、虚拟按键动态隐藏,应用可以使用完整的屏幕空间,按照Google的说法,给用户一种身临其境的体验。
最近几个项目中都有实现沉浸式状态栏的需求,其实就是状态栏和标题栏色调保持一直。难点还是Android的版本适配问题。主要时4.4系统和5.0+的系统兼容性。4.4以下的就不要想了不支持状态栏颜色修改。
- 先上干货,再来慢慢讲解:(注意:WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS这个标记在4.4以上都是生效的,但是发现在5.0以上一些手机呈现背景色为半透明的黑色,并非全透明,所以在5.0及以上的系统还是用如下的方法是吧。)
系统版本在4.4及以上5.0以下的:
------------
------------
//4.4到5.0 if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){ //透明状态栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); //透明导航栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); }
系统版本在5.0及以上的:
------------
//5.0版本及以上 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); getWindow().setStatusBarColor(Color.TRANSPARENT); getWindow().setNavigationBarColor(Color.BLACK); }
-
首先看下5.0及以上机型默认情况下的界面:默认下状态栏取styles.xml下的colorPrimaryDark值这里为红色;标题栏取colorPrimary值这里为蓝色;activity的背景色为白色。
-
设置5.0及以上的代码后在5.0以上的机型上显示如下图:为了便于区分将背景设为粉色,此时发现activity的内容填充满整个屏幕。当通过setSystemUiVisibility(int visibility)方法设置:
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN属性时表示:Activity全屏显示,但是状态栏不会被覆盖掉,而是正常显示,只是Activity顶端布局会被覆盖住;View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:隐藏导航栏;
View.SYSTEM_UI_FLAG_LAYOUT_STABLE:这个标记来帮助你的应用维持一个稳定的布局(这句话真他妈不能理解)。
然后设置状态栏透明就能实现如下图的效果,不然状态栏会在上面盖住图中的hello world。通过setStatusBarColor(Color.TRANSPARENT)设置透明(这个方法只有在使用了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 并且没有使用 FLAG_TRANSLUCENT_STATUS的时候才有效。)。
但是像下图的效果就很尴尬activity的内容填充到状态栏了,这个时候需要在布局文件里加入android:fitsSystemWindows="true":如果为true,将调整系统窗口布局以适应你自定义的布局,也就是调整了留出来系统的状态栏空间。最终效果如下图2。 当然状态栏可以不设置透明而是根据需求设置相应的颜色,标题栏也同样,整体效果达成沉浸式就ok(当然我这标题栏蓝色就不是了,修改后的效果如图3)。
-
另外附上setSystemUiVisibility(int visibility)的其他属性说明:
- SYSTEM_UI_FLAG_VISIBLE——显示状态栏和导航栏
- SYSTEM_UI_FLAG_LOW_PROFILE——此模式下,状态栏的图标可能是暗的
- SYSTEM_UI_FLAG_HIDE_NAVIGATION——隐藏导航栏
- SYSTEM_UI_FLAG_FULLSCREEN——全屏,隐藏状态栏和导航栏
- SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN——全屏,隐藏导航栏,状态栏浮在布局上。
- SYSTEM_UI_FLAG_IMMERSIVE——沉浸式:半透明的状态栏和导航栏
- SYSTEM_UI_FLAG_IMMERSIVE_STICKY——粘性沉浸式
- INVISIBLE —— Activity全屏显示,隐藏状态栏
-
4.4-5.0的机型上默认情况如下图:状态栏默认为黑色,并且只提供了translucent system bars(半透明系统栏,即顶部状态栏和底部导航栏)
-
添加4.4-5.0的代码后在4.4的机型上显示如下图:状态栏半透明了(布局里任然需要设置android:fitsSystemWindows="true",这里为了展示将activity的背景设为绿色了)。4.4上面想要修改状态栏的颜色就稍微要麻烦一点了,因为没有提供5.0以上的直接换状态栏颜色的方法。那么办了?有一种偷懒的方法:将activity的背景设置为状态栏需要的颜色,然后在acitivity的跟布局下面(也就是标题栏下的内容设置成其他需要的颜色)但是这存在局限性就是每个activity都需要单独设置内容布局颜色。 那还有其他什么办法? 这就需要我们自己生成一个和状态栏大小相同的半透明矩形条,让他代替系统状态栏。
-
具体代码见下: 调用setStatusBarColor(Activity activity,int color)就可以设置状态栏的颜色,实现原理和过程自行百度了解。(注意代码中绘制和状态栏高度相同的矩形view时动态设置了它的id,这个id写在了ids.xml里了,findVewById的时候可以通过R.id.statusbarutil_fake_status_bar_view调用)
//设置4.4系统状态栏的颜色方法
private static void setStatusBarColor(Activity activity,int color){
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
View fakeStatusBarView = decorView.findViewById(R.id.statusbarutil_fake_status_bar_view);
if (fakeStatusBarView != null) {
if (fakeStatusBarView.getVisibility() == View.GONE) {
fakeStatusBarView.setVisibility(View.VISIBLE);
}
fakeStatusBarView.setBackgroundColor(color);
} else {
decorView.addView(createStatusBarView(activity,color));
}
setRootView(activity);
}
// 绘制一个和状态栏一样高的矩形
private static View createStatusBarView(Activity activity,int color) {
View statusBarView = new View(activity);
LinearLayout.LayoutParams params =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity));
statusBarView.setLayoutParams(params);
statusBarView.setBackgroundColor(color);
//动态设置view的id
statusBarView.setId(R.id.statusbarutil_fake_status_bar_view); return statusBarView;}// 获得状态栏高度private static int getStatusBarHeight(Context context) { int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); return context.getResources().getDimensionPixelSize(resourceId);}//设置根布局参数private static void setRootView(Activity activity) { ViewGroup parent = (ViewGroup) activity.findViewById(android.R.id.content); for (int i = 0, count = parent.getChildCount(); i < count; i++) { View childView = parent.getChildAt(i); if (childView instanceof ViewGroup) { childView.setFitsSystemWindows(true); ((ViewGroup) childView).setClipToPadding(true); } }}
-
调用setStatusBarColor(Activity activity,int color)后的效果图如下:文中的标题栏可以通过设置主题NoActionBa取消掉添加自己的标题栏。