沉浸式状态栏的实现原理很简单,就是将状态栏隐藏掉,然后在原来状态栏的位置添加一个和状态栏大小一模一样的View,这个View的颜色定义成和Toolbar一样的颜色就行了
在styles.xml文件中设置主题样式为NoActionBar
这样系统自带的ActionBar就没有了,需要自己在布局文件中添加Toolbar
透明化状态栏
/**
* 沉浸式状态栏工具类
*/
public class StatusBarUtils {
/**
* 透明化状态栏
*/
public static void transparentStatusBar(Activity act, boolean fitWindow) {
Window window = act.getWindow();
//透明状态栏
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//获取根布局
ViewGroup root = (ViewGroup) act.findViewById(android.R.id.content);
View firstChild = root.getChildAt(0);
if (firstChild != null) {
//设置root的第一个子View,使其为系统View预留空间.
firstChild.setFitsSystemWindows(fitWindow);
}
}
}
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
这行代码的作用就是使状态栏透明化
//获取根布局
ViewGroup root = (ViewGroup) act.findViewById(android.R.id.content);
View firstChild = root.getChildAt(0);
if (firstChild != null) {
//设置root的第一个子View,使其为系统View预留空间.
firstChild.setFitsSystemWindows(fitWindow);
}
这一串代码的作用是就是在布局文件的最外层控件上添加了一个android:fitsSystemWindows="true"
属性,当然也可以在布局文件中添加,就像下面这样
android:fitsSystemWindows="true"
的效果是为系统View预留空间,也就是将状态栏的位置空出来,它的默认值是false。下图是对比这个属性在状态栏透明
时设置为true和false的区别
创建状态栏
public static View createStatusBar(Context context, int color) {
//方法原理:
//添加一个和状态栏高、宽相同的指定颜色的View来覆盖被透明化的状态栏
View statusBar = new View(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(context));
statusBar.setLayoutParams(params);
statusBar.setBackgroundColor(color);
return statusBar;
}
这部分没什么好讲的,就是单纯的创建一个状态栏,状态栏的颜色通过参数设置
public static int getStatusBarHeight(Context context) {
int statusBarHeight = -1;
try {
Class clazz = Class.forName("com.android.internal.R$dimen");
//通过反射获取状态栏高度这个成员变量
Field status_bar_height = clazz.getField("status_bar_height");
Object obj = clazz.newInstance();
int height = Integer.parseInt(status_bar_height.get(obj).toString());
statusBarHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusBarHeight;
}
这个方法用于获取状态栏的高度,不用在意方法的实现细节,只需要知道这个方法能够获取到状态栏的高度就行了
将创建的状态栏添加到布局上
public static void addStatusBar(Activity act, int color) {
int resource = act.getResources().getColor(color);
//创建状态栏
View statusBar = createStatusBar(act, resource);
//获取根布局
ViewGroup root = (ViewGroup) act.findViewById(android.R.id.content);
//将状态栏添加到根布局的第一个子布局位置
root.addView(statusBar, 0);
}
这个方法的第二个参数是传入颜色的id,例如R.color.colorPrimary
这样的参数。
这个方法的作用是将状态栏添加到布局上去,什么意思?画个图解释
root.addView(statusBar, 0);
这行代码就是将状态栏添加到根布局下面,参数
0
代表位置
需要注意的是根布局不是指布局文件中最外层的控件
我的布局文件是这样的,根布局并不是指LinearLayout
最后一步
/**
* 绘制状态栏
* @param act
* @param color
*/
public static void drawableStatusBar(Activity act, int color) {
transparentStatusBar(act, true);
addStatusBar(act, color);
}
添加上这个方法工具类就完成了,下面是完整的代码
/**
* 沉浸式状态栏工具类
*/
public class StatusBarUtils {
/**
* 绘制状态栏
* @param act
* @param color
*/
public static void drawableStatusBar(Activity act, int color) {
transparentStatusBar(act, true);
addStatusBar(act, color);
}
/**
* 透明化状态栏
*
* @param act
*/
public static void transparentStatusBar(Activity act, boolean fitWindow) {
Window window = act.getWindow();
//透明状态栏
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
//获取根布局
ViewGroup root = (ViewGroup) act.findViewById(android.R.id.content);
View firstChild = root.getChildAt(0);
if (firstChild != null) {
//设置 root 的第一个子 View . 使其为系统 View 预留空间.
firstChild.setFitsSystemWindows(fitWindow);
}
}
/**
* 添加状态栏
*
* @param act
* @param color
*/
public static void addStatusBar(Activity act, int color) {
int resource = act.getResources().getColor(color);
//创建状态栏
View statusBar = createStatusBar(act, resource);
//获取根布局
ViewGroup root = (ViewGroup) act.findViewById(android.R.id.content);
//将状态栏添加到根布局下的第一个子布局位置
root.addView(statusBar, 0);
}
/**
* 创建一个状态栏
*
* @param context
* @param color
* @return
*/
public static View createStatusBar(Context context, int color) {
//方法原理:
//添加一个和状态栏高、宽相同的指定颜色的View来覆盖被透明化的状态栏
View statusBar = new View(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(context));
statusBar.setLayoutParams(params);
statusBar.setBackgroundColor(color);
return statusBar;
}
/**
* 获取状态栏高度
*
* @param context
* @return
*/
public static int getStatusBarHeight(Context context) {
int statusBarHeight = -1;
try {
Class clazz = Class.forName("com.android.internal.R$dimen");
//通过反射获取状态栏高度这个成员变量
Field status_bar_height = clazz.getField("status_bar_height");
Object obj = clazz.newInstance();
int height = Integer.parseInt(status_bar_height.get(obj).toString());
statusBarHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e) {
e.printStackTrace();
}
return statusBarHeight;
}
}
在onCreate()
方法中调用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StatusBarUtils.drawableStatusBar(this, R.color.colorPrimary);
}
效果如下