在上一个博文 Anroid沉浸式状态栏中提到了,画了一个图,这个图简单将我们的状态栏分为不同的2个维度来看状态栏。其中涉及的概念我不在赘诉,请返到Anroid沉浸式状态栏再去认识下这几个概念。本文中提到的[上节]就是Anroid沉浸式状态栏这篇文章。**
实现
由于[上节]提到了基本的实现方法和一些基本概念,但是没有实际操作和演示,那我们现在就来一步步来去实现我们提到的三种状态栏的实现过程。
全屏模式下的透明状态栏
全屏模式下的透明状态栏,其他app实现这样方式我们肯定见过,如我们的启动页很多情况下就是全屏模式,但是这个还是和我们说的不太一样,不过今天我们介绍的这个是透明状态栏,但是仍然又有出入。
如下图是网易新闻的启动页:
但是不是我们需要的效果,这种是全屏模式时,当前页面获取焦点就显示一个有一定透明度的暗色状态栏。
网易新闻这种才是真正的浸入式状态栏,这个沉浸式让郭神讲的很透彻 –Android状态栏微技巧,带你真正理解沉浸式模式
我们希望的是小米天气的这种:
内容部分可以延伸到状态栏,且状态栏是透明的,无背景色,也就是我们的全屏模式。
按照我们上节拿来实践下。
1 2 3 4 5 6 7
| public static void setFullSreen(Activity activity){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
} }
|
我将一个图片铺满contentView。
这个截图是在4.4上完成的。
但是在6.0上的效果还差强人意:
这个是在我的N5手机上跑的,上面有灰色的阴影。不是完全透明,和我们的小米天气不太一样,好了还是用到上节的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public static void setFullSreen(Activity activity){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window window = activity.getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); }else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
} }
|
这样就可以使得状态栏也透明了。
彩色状态栏
可能有些人会迷惑,为什么我们要设置彩色状态栏,在5.0可以直接设置主题来设置的,我要告诉你的是我们希望4.4上也有彩色的状态栏。上节我们提到了彩色状态栏的实现方法:就是先设置为屏幕模式下的透明状态栏,再在透明状态栏的垂直下方放置一个和状态栏同样高宽的view,我们操作他这个空白view的颜色,即可实现彩色状态栏。
具体实现是参考猴子的一个开源项目StatusBarUtil里的中代码,可能略有改动,已经告知猴子,得到他本人授权。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
|
public static void setColor(Activity activity, @ColorInt int color, int statusBarAlpha){
setFullSreen(activity); addStatusBarBehind(activity,color,statusBarAlpha);
}
public static void addStatusBarBehind(Activity activity, @ColorInt int color, int statusBarAlpha) { ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); int count = decorView.getChildCount(); if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) { decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha)); } else { StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha); decorView.addView(statusView); } setRootView(activity); }
private static void setRootView(Activity activity) { ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); ViewCompat.setFitsSystemWindows(rootView,false); rootView.setClipToPadding(true); }
private static StatusBarView createStatusBarView(Activity activity, int color, int alpha) { StatusBarView statusBarView = new StatusBarView(activity); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setLayoutParams(params); statusBarView.setBackgroundColor(calculateStatusColor(color, alpha)); 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 int calculateStatusColor(int color, int alpha) { float a = 1 - alpha / 255f; int red = color >> 16 & 0xff; int green = color >> 8 & 0xff; int blue = color & 0xff; red = (int) (red * a + 0.5); green = (int) (green * a + 0.5); blue = (int) (blue * a + 0.5); return 0xff << 24 | red << 16 | green << 8 | blue; }
|
其中状态栏的view就是一个简单的view,贴出来的这个类吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class StatusBarView extends View {
public StatusBarView(Context context, AttributeSet attrs,int style) { super(context, attrs,style); }
public StatusBarView(Context context, AttributeSet attrs) { super(context, attrs); }
public StatusBarView(Context context) { super(context); }
}
|
搞定,我们就可以来动态改变状态栏的颜色了。
calculateStatusColor 方法中的alpha是0-255的,0的时候其实是不透明的,当设置255相当于statusview背景透明,即为默认色黑色。
可用的函数是public static void setColor(Activity activity, @ColorInt int color, int statusBarAlpha)
和setFullSreen
小结
Now现在这个工具类就算是OK,对于代码的侵入基本上为零,直接拿来当工具类,不用改主题,简单易容用。也为大家提供一个思路,这个只是实现的基本功能,一些复杂的定制的情况,可以随机应变,自由组合使用。猴子的StatusBarUtil可以参考下,也希望大家多提issues,使这个项目更加完善。
实现状态栏,无非是将4.4-5.0 和5.0+的分别实现,当然配合decorview和 ViewCompat.setFitsSystemWindows(view,boolean)使用效果更佳。
拓展阅读
在改变状态栏颜色时,我们需要注意的是默认的状态栏字体颜色都是黑色的,但是若是背景为暗色,上面的时间、电量等还等看到很清晰,但是若是遇到了全屏模式下状态栏垂直下方的view是白色的或者接近白色,那岂不是看不见状态栏上的字么?
是的!
所以有人提出需要改状态栏的字体颜色了,这个在知乎上火了一阵,所以把这个拓展部分留一个知乎的链接 —-android开发,修改状态栏字体颜色?