状态栏的分析

一.在介绍状态栏之前,我们先回顾一下window下视图布局:

1.1 ContentView:我们通过activity.findViewById(Window.ID_ANDROID_CONTENT)获取的View,即得到是setContentView的View,实质是FrameLayout

1.2 ContentParent: ContentView的Parent,实质是LinearLayout.

1.3 ChildView : ContentView的第一个子View,即是Layout布局文件

再介绍一下相关的函数:

  1. fitsSystemWindows, 该属性可以设置是否为系统 View 预留出空间, 当设置为 true 时,会预留出状态栏的空间.

  2. ContentView, 实质为 ContentFrameLayout, 但是重写了 dispatchFitSystemWindows 方法, 所以对其设置 fitsSystemWindows 无效.

  3. ContentParent, 实质为 FitWindowsLinearLayout, 里面第一个 View 是 ViewStubCompat, 如果主题没有设置 title ,它就不会 inflate .第二个 View 就是 ContentView.

5.0以上的处理:

自5.0引入 Material Design ,状态栏对开发者更加直接,可以直接调用 setStatusBarColor 来设置状态栏的颜色.

1.全屏模式:

Window window = activity.getWindow();
//设置透明状态栏,这样才能让 ContentView 向上
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 

//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
//设置状态栏颜色
window.setStatusBarColor(statusColor);

ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
    //注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View . 使其不为系统 View 预留空间.
    ViewCompat.setFitsSystemWindows(mChildView, false);
}

2.着色模式:

Window window = activity.getWindow();
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 

//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
//设置状态栏颜色
window.setStatusBarColor(statusColor);

ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
    //注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View . 预留出系统 View 的空间.
    ViewCompat.setFitsSystemWindows(mChildView, true);
}

4.4-5.0的处理:

4.4-5.0因为没有直接的 API 可以调用,需要自己兼容处理,网上的解决方法基本都是创建一下高度为状态栏的 View ,通过设置这个 View 的背景色来模拟状态栏. 这里我尝试了三种方法来兼容处理.

方法1: 向 ContentView 添加假 View , 设置 ChildView 的 marginTop 属性来模拟 fitsSystemWindows .

1. 全屏模式

Window window = activity.getWindow();
ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);

//首先使 ChildView 不预留空间
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
    ViewCompat.setFitsSystemWindows(mChildView, false);
}

int statusBarHeight = getStatusBarHeight(activity);
//需要设置这个 flag 才能设置状态栏
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//避免多次调用该方法时,多次移除了 View
if (mChildView != null && mChildView.getLayoutParams() != null && mChildView.getLayoutParams().height == statusBarHeight) {
    //移除假的 View.
    mContentView.removeView(mChildView);
    mChildView = mContentView.getChildAt(0);
}
if (mChildView != null) {
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mChildView.getLayoutParams();
    //清除 ChildView 的 marginTop 属性
    if (lp != null && lp.topMargin >= statusBarHeight) {
        lp.topMargin -= statusBarHeight;
        mChildView.setLayoutParams(lp);
    }
}

2.着色模式:

Window window = activity.getWindow();
ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);

//First translucent status bar.
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
int statusBarHeight = getStatusBarHeight(activity);

View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mChildView.getLayoutParams();
    //如果已经为 ChildView 设置过了 marginTop, 再次调用时直接跳过
    if (lp != null && lp.topMargin < statusBarHeight && lp.height != statusBarHeight) {
        //不预留系统空间
        ViewCompat.setFitsSystemWindows(mChildView, false); 
        lp.topMargin += statusBarHeight;
        mChildView.setLayoutParams(lp);
    }
}

View statusBarView = mContentView.getChildAt(0);
if (statusBarView != null && statusBarView.getLayoutParams() != null && statusBarView.getLayoutParams().height == statusBarHeight) {
    //避免重复调用时多次添加 View
    statusBarView.setBackgroundColor(statusColor);
    return;
}
statusBarView = new View(activity);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
statusBarView.setBackgroundColor(statusColor);
//向 ContentView 中添加假 View
mContentView.addView(statusBarView, 0, lp);

方法2: 向 ContentParent 添加假 View ,设置 ContentView 和 ChildView 的 fitsSystemWindows.

全屏模式:

Window window = activity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
ViewGroup mContentParent = (ViewGroup) mContentView.getParent();

View statusBarView = mContentParent.getChildAt(0);
if (statusBarView != null && statusBarView.getLayoutParams() != null && statusBarView.getLayoutParams().height == getStatusBarHeight(activity)) {
    //移除假的 View
    mContentParent.removeView(statusBarView);
}
//ContentView 不预留空间
if (mContentParent.getChildAt(0) != null) {
    ViewCompat.setFitsSystemWindows(mContentParent.getChildAt(0), false);
}

//ChildView 不预留空间
View mChildView = mContentView.getChildAt(0);
if (mChildView != null) {
    ViewCompat.setFitsSystemWindows(mChildView, false);
}

着色模式(会有一条黑线,无法解决):

Window window = activity.getWindow();  
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);  
  
ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);  
ViewGroup mContentParent = (ViewGroup) mContentView.getParent();  
  
View statusBarView = mContentParent.getChildAt(0);  
if (statusBarView != null && statusBarView.getLayoutParams() != null && statusBarView.getLayoutParams().height == getStatusBarHeight(activity)) {  
    //避免重复调用时多次添加 View  
    statusBarView.setBackgroundColor(statusColor);  
    return;  
}  
  
//创建一个假的 View, 并添加到 ContentParent  
statusBarView = new View(activity);  
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,  
        getStatusBarHeight(activity));  
statusBarView.setBackgroundColor(statusColor);  
mContentParent.addView(statusBarView, 0, lp);  
  
//ChildView 不需要预留系统空间  
View mChildView = mContentView.getChildAt(0);  
if (mChildView != null) {  
    ViewCompat.setFitsSystemWindows(mChildView, false);  
}  

方法3:向 ContentView 添加假 View , 设置 ChildView 的 fitsSystemWindows.

全屏模式:

Window window = activity.getWindow();  
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);  
  
ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);  
View statusBarView = mContentView.getChildAt(0);  
//移除假的 View  
if (statusBarView != null && statusBarView.getLayoutParams() != null && statusBarView.getLayoutParams().height == getStatusBarHeight(activity)) {  
    mContentView.removeView(statusBarView);  
}  
//不预留空间  
if (mContentView.getChildAt(0) != null) {  
    ViewCompat.setFitsSystemWindows(mContentView.getChildAt(0), false);  
}  

着色模式:

Window window = activity.getWindow();  
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);  
  
ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);  
int statusBarHeight = getStatusBarHeight(activity);  
  
View mTopView = mContentView.getChildAt(0);  
if (mTopView != null && mTopView.getLayoutParams() != null && mTopView.getLayoutParams().height == statusBarHeight) {  
    //避免重复添加 View  
    mTopView.setBackgroundColor(statusColor);  
    return;  
}  
//使 ChildView 预留空间  
if (mTopView != null) {  
    ViewCompat.setFitsSystemWindows(mTopView, true);  
}  
  
//添加假 View  
mTopView = new View(activity);  
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);  
mTopView.setBackgroundColor(statusColor);  
mContentView.addView(mTopView, 0, lp); 

 

转载于:https://my.oschina.net/quguangle/blog/1550041

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值