背景
在Android4.4之前,状态栏都是单调的黑色条状,4.4之后Android开始支持状态栏的个性定制,如:变色半透明和全透明。国内很多将这种变色或透明状态栏称为“沉浸式状态栏”,其实官方并无此叫法,国内最先叫起这高大上的名称,应该“功劳”归于这里:MIUI 6 沉浸式状态栏调用方法,后来估计是时间长了,叫的人也多了后,大家便都习惯了、默认就这种叫了。
效果
首先来了看看Android5.0和4.4在效果上的区别:
如上图,5.0系统的状态栏是单纯颜色,而4.4系统中,无论设置了变色、半透明或全透明,都会自带一个黑色渐变效果。
实现的原理
除了效果有所区别,在实现原理方面,它们也有所不同,5.0系统实现变色比较简单,因为Window类里已经提供了一个叫setStatusBarColor(int color)的方法,直接调用即可,要注意的是,setStatusBarColor方法设置的状态栏颜色其实是在默认黑色状态栏的上面加上一层,所以color参数的alpha值无论怎样设置都只是上层颜色的透明,即并不能做到整个状态栏透明或半透明;4.4系统因为本身没有提供现成的方法,所以需要用些小手段,这种小手段可以实现全透明、半透明以及颜色状态栏,步骤大概是这样:设置Window的Flags带FLAG_TRANSLUCENT_STATUS,然后根布局的fitsSystemWindows和clipToPadding参数为true,使其可以布局基于系统状态栏和使控件的绘制区域不在padding里面。如果只是做全透明状态栏,到了这步已经可以看到效果了。但想做成带颜色或半透明的话,还需进一步的处理。因为此时状态栏已经处理透明,那么手动在顶级View上添加一个跟状态栏大小一样的View,那样看上去,便是状态栏变颜色,如果添加的View做成半透明,那么便是半透明状态栏了。
到这,我们来想想,因为5.0系统里的setStatusBarColor(intcolor)方法不能直接做成半透明状态栏,如果在实现全透明状态栏步骤中,系统刚好是5.0呢,能不能不用手动生成状态栏大小的View,而是直接用setStatusBarColor(int color)方法并使color参数的alpha值带透明,那样能否实现状态栏的半透明的效果的呢?答案是确定的。
实现的代码
接下来看看完整的代码的实现:
/**
* 设置状态栏颜色
*
* @param activity 需要设置的activity
* @param color 状态栏颜色值
*/
public static void setColor(Activity activity, int color) {
int alpha = Color.alpha(color);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && alpha == 255) { // 安卓5.0及以上而且非带透明,可以直接使用setStatusBarColor处理
setLollipopStatusBarColor(activity, color);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // 安卓4.4,需要此小手段
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// 获取根布局View并设置相应参数
ViewGroup rootView = (ViewGroup)((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
rootView.setFitsSystemWindows(true);
rootView.setClipToPadding(true);
// 非全透明情况下
if (alpha != 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// 5.0系统直接设置状态栏颜色
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
setLollipopStatusBarColor(activity, color);
} else {
// 4.4系统生成一个跟状态栏一样高的矩形View 添加到顶层View
View statusView = createStatusBarView(activity, color);
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
decorView.addView(statusView);
}
}
}
}
/**
* 安卓5.0及以上设置状态栏颜色
*
* @param activity 需要设置的activity
* @param color 状态栏颜色值
*/
private static void setLollipopStatusBarColor(Activity activity, int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); //需要设置 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 才能调用 setStatusBarColor 来设置状态栏颜色
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().setStatusBarColor(color);
}
}
/**
* 生成一个和状态栏大小相同的矩形View
*
* @param activity 需要设置的activity
* @param color 状态栏颜色值
* @return 状态栏矩形条
*/
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);
return statusBarView;
}
/**
* 获取状态栏高度
*
* @param context context
* @return 状态栏高度
*/
private static int getStatusBarHeight(Context context) {
// 获得状态栏高度
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(resourceId);
}
调用很简单,假如我们把这封装到一个叫StatusBarUtil名的类,那么要置纯色或带透明颜色的状态栏,代码可以这样:
StatusBarUtil.setColor(this, getResources().getColor(R.color.color));
为了方便外边的调用全透明情况,在StatusBarUtil类里,可以封装一个setTransparent方法:
/**
* 设置状态栏透明
* 适用于图片作为背景的界面,此时需要图片填充到状态栏
* @param activity 需要设置的activity
*/
public static void setTransparent(Activity activity) {
setColor(activity, Color.argb(0, 0, 0, 0));
}
此时,如果需要设置一个全透明的状态栏,调用代可以这样:
StatusBarUtil.setTransparent(this);