在android4.4以前状态栏只能是黑色,在4.4中带来了windowTranslucentStatus 这一特性,状态栏的颜色就可以感觉自己的需求改变颜色了,那为什么叫沉浸式状态栏呢?这个叫法是叫的人多人,大家都约定俗称了。废话不多说,首先上一张效果图。
此demo的布局文件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#FF0000"
android:textColor="#FFFFFF"
android:text="沉浸式状态栏"
/>
</LinearLayout>
其实实现沉浸式状态栏非常的简单,两行代码就可以实现,把下面两行代码添加到你activity的 setContentView方法之后
//当系统版本为4.4或者4.4以上时可以使用沉浸式状态栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
然后你会发现,沉浸式状态栏确实是实现了,但是TextView直接和状态栏重叠了,这还没有达到我们想要的效果,效果如下图
为了解决TextView和状态栏的重叠方式有两种方式,第一种方式是给刚刚的TextView的布局文件添加android:fitsSystemWindows="true" , android:clipToPadding="true"这两个属性,第二种方式是在布局文件中放置一个隐藏的View,通过代码获取状态栏的高度,然后动态的设置view的颜色和高度,让其填充整个状态栏
第一种方式
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:fitsSystemWindows="true"
android:clipToPadding="true"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#FF0000"
android:textColor="#FFFFFF"
android:text="沉浸式状态栏"
/>
</LinearLayout>
第二种方式
第二种方式实现起来麻烦一点,但是个人推荐使用这种方式,不然让TexTView的文本进行居中显示时会很不准
先看看布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:id="@+id/ll_fill"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:orientation="vertical"
android:background="#FF0000"
android:visibility="gone">
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#FF0000"
android:textColor="#FFFFFF"
android:text="沉浸式状态栏"
/>
</LinearLayout>
再看看在Activity中的代码
//当系统版本为4.4或者4.4以上时可以使用沉浸式状态栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
LinearLayout ll_fill = (LinearLayout) findViewById(R.id.ll_fill);
ll_fill.setVisibility(View.VISIBLE);
//获取到状态栏的高度
int statusHeight = getStatusBarHeight();
Log.e("399", "statusHeight" + statusHeight);
//动态的设置隐藏布局的高度
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) ll_fill.getLayoutParams();
params.height = statusHeight;
ll_fill.setLayoutParams(params);
}
状态栏的高度是通过反射的方式获取的,获取方式如下:
/**
* 通过反射的方式获取状态栏高度
*
* @return
*/
private int getStatusBarHeight() {
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x = Integer.parseInt(field.get(obj).toString());
return getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
实现后的效果图:
以上是在运行android4.4.4的小米4上显示的效果,运行在android5.0及以上的效果如下:
你会发现状态栏并不是完全透明的,网上找了很久,最后在github的一个开源项目中找到了答案,解决方式如下:
在Activity的onCreate中添加
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
else {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
LinearLayout ll_fill = (LinearLayout) findViewById(R.id.ll_fill);
ll_fill.setVisibility(View.VISIBLE);
//获取到状态栏的高度
int statusHeight = getStatusBarHeight();
Log.e("399", "statusHeight" + statusHeight);
//动态的设置隐藏布局的高度
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) ll_fill.getLayoutParams();
params.height = statusHeight;
ll_fill.setLayoutParams(params);
然后就全透明啦
最后,找到一个实现沉浸式状态栏的开源库,地址
https://github.com/laobie/StatusBarUtil
更具这个开源库简单的抽取了一个工具类StatusBarUtil,可以直接拿来用
package com.hand.gaoli.utils;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import com.hand.gaoli.widget.StatusBarView;
import java.lang.reflect.Field;
/**
* Created by cool on 2017/1/10.
*/
public class StatusBarUtil {
public static void setImmerse(Activity activity,int color){
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
initImmerse(activity);
addStatusView(activity,color);
setRootView(activity);
}
/**
* 设置沉浸式状态栏
*/
private static void initImmerse(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
/**
* 设置根布局参数
*/
private static void addStatusView(Activity activity,int color) {
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
int count = decorView.getChildCount();
if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {
decorView.getChildAt(count - 1).setBackgroundColor(color);
} else {
StatusBarView statusView = createStatusBarView(activity, color);
decorView.addView(statusView);
}
}
/**
* 设置根布局参数
*/
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);
}
}
}
private static StatusBarView createStatusBarView(Activity activity,int color) {
StatusBarView view = new StatusBarView(activity);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,getStatusBarHeight(activity));
view.setLayoutParams(params);
view.setBackgroundColor(color);
return view;
}
/**
* 通过反射的方式获取状态栏高度
*
* @return
*/
public static int getStatusBarHeight(Context context) {
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object obj = c.newInstance();
Field field = c.getField("status_bar_height");
int x = Integer.parseInt(field.get(obj).toString());
return context.getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
StatusBarView
package com.hand.gaoli.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by cool on 2017/1/10.
*/
public class StatusBarView extends View {
public StatusBarView(Context context) {
super(context);
}
public StatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public StatusBarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
使用:
//设置沉浸式状态栏
StatusBarUtil.setImmerse(this, getResources().getColor(R.color.main_color));