开始,想写一个设置状态栏的通用类,之后又需要结合小米和6.0之后状态栏字体变为黑色等,就找了些资料。
一下子就实现了功能,觉得也挺快的。然后做了一些就想了解一下一个Activity的布局到底有那些view,因为,我们对一些没有放出接口的方法,只能用反射才能获取,然后再设置属性。所以想着就了解一下Activity的View布局
开始都是copy代码,所以很简单的设置了以下方法。
这边加入使用的测试手机是 红米2
这边是只考虑了api19的情况,就先放简单的代码
public static void setStatusBarTranslucent(Activity activity){
Window window = activity.getWindow();
if (Build.VERSION.SDK_INT >= 19) {
//透明状态栏
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
public static int getStatusBarHeight(Context context){
int barId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
return context.getResources().getDimensionPixelSize(barId);
}
public static void addStatusBarView(Activity activity){
View view = new View(activity);
view.setBackgroundColor(Color.RED);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
getStatusBarHeight(activity));
ViewGroup group = activity.findViewById(android.R.id.content);
group.addView(view, lp);
}
public static boolean setMIUIBar(Activity activity, boolean dark){
Window window = activity.getWindow();
if (window != null) {
Class clazz = window.getClass();
try {
int modeFlag;
Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
modeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
if (dark) {
//透明状态栏 黑色字体
extraFlagField.invoke(window, modeFlag, modeFlag);
}else {
//白色字体
extraFlagField.invoke(window, 0, modeFlag);
}
//开发版 7.7.13及以后版本采用了安卓6.0系统API
setBarMode(activity, dark);
return true;
}catch (Exception e){
}
}
return false;
}
public static void setBarMode(Activity activity, boolean dark){
View decorView = activity.getWindow().getDecorView();
if (Build.VERSION.SDK_INT >= 23) {
if (dark) {
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}else {
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
}
}
然后我们设置到Activity上面
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("-s-", "sdk = "+ Build.VERSION.SDK_INT);
StatusBarUtils.setStatusBarTranslucent(this);
StatusBarUtils.addStatusBarView(this);
StatusBarUtils.setMIUIBar(this, true);
}
效果如下
到目前为止我们确实就完成了设置状态栏的背景颜色,修改状态栏的字体了!
本来这样就结束了,之后也就稍微写规范点就可以实现通用类的设置了。
但是,之后想看看到底Activity底下的View到底是什么。
从上面的设置我可以知道两个很有用的信息。
1.android.R.id.content
2.getWindow().getDecorView()
这两个到底代表什么呢
我对代码做了如下修改
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("-s-", "sdk = "+ Build.VERSION.SDK_INT);
// StatusBarUtils.setStatusBarTranslucent(this);
//
// StatusBarUtils.addStatusBarView(this);
//
// StatusBarUtils.setMIUIBar(this, true);
ViewGroup decorView = (ViewGroup) getWindow().getDecorView();
Log.e("-s-", "decorView getChildCount = "+ decorView.getChildCount());
for (int i = 0; i < decorView.getChildCount(); i++) {
Log.e("-s-", "getClassName = "+ decorView.getChildAt(i).getClass().getName());
}
ViewGroup content = findViewById(android.R.id.content);
Log.e("-s-", "content getChildCount = "+ content.getChildCount());
for (int i = 0; i < content.getChildCount(); i++) {
Log.e("-s-", "getClassName = "+ content.getChildAt(i).getClass().getName());
}
}
}
观察到如下log
E/-s-: sdk = 19
E/-s-: decorView getChildCount = 1
E/-s-: getClassName = android.widget.LinearLayout
E/-s-: content getChildCount = 1
E/-s-: getClassName = android.support.constraint.ConstraintLayout
我查了下百度
一、DecorView为整个Window界面的最顶层View。
二、DecorView只有一个子元素为LinearLayout。代表整个Window界面,包含通知栏,标题栏,内容显示栏三块区域。
三、LinearLayout里有两个FrameLayout子元素。
原文 Android DecorView浅析
为了看下实际我也打开了Android Device Monitor查看
大体上我们就可以通过上面的布局知道了两个的关联了。
而且我们开始设置的时候,发现添加BarView是在android.R.id.content
中添加一个高度和默认状态栏一样高度的view,所以我就试验一下取消addStatusBarView
的注释
E/-s-: sdk = 19
E/-s-: decorView getChildCount = 1
E/-s-: getClassName = android.widget.LinearLayout
E/-s-: content getChildCount = 2
E/-s-: getClassName = android.support.constraint.ConstraintLayout
E/-s-: getClassName = android.view.View
之后我把setStatusBarTranslucent
也打开了,然后就是正常的设置了状态栏的颜色。
然后我又做了添加多个addStatusBarView
,发现确实添加了多个barview。
至此我们可以确认,状态栏是单独一个由系统控制好了的,然后我们修改状态栏的颜色其实就是设置flag将系统默认的状态栏view去掉。然后让布局能够整个填充,然后我们在content 这个view中加入新的barview和原来的setContentView(R.layout.activity_main)之后我们在未最外层添加一个android:fitsSystemWindows="true"
属性让setContentView加入的view能够在content已经添加好的view之下,就实现了修改状态栏颜色。
大概就是这样吧!
为了证实 我做了如下实验
我不设置最外层的fitsSystemWindows属性,而是为最外层添加一个topMargin
修改代码如下
for (int i = 0; i < content.getChildCount(); i++) {
Log.e("-s-", "getClassName = "+ content.getChildAt(i).getClass().getName());
// content.getChildAt(0).setFitsSystemWindows(true);
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) content.getChildAt(0).getLayoutParams();
lp.topMargin = StatusBarUtils.getStatusBarHeight(this);
content.getChildAt(0).setLayoutParams(lp);
}
最后的结果却是和设置fitsSystemWindows属性一模一样!
用了这么久,以前也知道DecorView和content,只是没这么深入的了解一下。趁着这次设置就实地的深入学习了下。
白底黑字!Android浅色状态栏黑色字体模式
Android DecorView浅析