Android状态栏适配源码解析。

前言

Android状态栏透明,状态栏着色与沉浸是我们必须要会弄的东西。 这里告诉你各个版本怎么适配,为什么需要分版本来适配!

怎么使用

状态栏透明

  • 5.0以上:
 if (Build.VERSION.SDK_INT >= 21) {
    View decorView = getWindow().getDecorView();
    int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
 // View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:
 //Activity布局全屏显示,但状态栏不会被隐藏覆盖,
 //状态栏依然可见,Activity顶端布局部分会被状态遮住。
 //SYSTEM_UI_FLAG_LAYOUT_STABLE :
 //防止状态栏隐藏,保证你使用fitSystemWindows时候,系统UI边界
 //始终不会变,依然存在可见.即使你隐藏了所有,他依然存在,增加了UI稳定性,
    decorView.setSystemUiVisibility(option);
    getWindow().setStatusBarColor(Color.TRANSPARENT);//状态栏颜色设置为透明。
}
  • 4.4到5.0之间
if(Build.VERSION.SDK_INT>=19){
   WindowManager.LayoutParams  myLayoutParams = getWindow().getAttributes();
   myLayoutParams.flags =(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS|myLayoutParams.flags);
   }
   //这里大家可能不懂 | 操作因为这里的flags都是只占一位的1的(如000001,000010,000100,001000),其实这里的位或操作就是将FLAG_TRANSLUCENT_STATUS的flags相加起来。详情可看

上面具体位或参数可见这片BLOG分析:
http://blog.csdn.net/luojiusan520/article/details/47696891。


状态栏上色

  • 5.0以上:
    官方新加入的API
 getWindow().setStatusBarColor(int Color);
 //想要什么颜色就用什么颜色,一步到位
  • 4.4到5.0之间
    这里由于官方没有给出设置状态栏的颜色API,所以我们需要使用先透明状态栏,然后fitSystemWindows==true,然后填充一个等高的纯色View,来模拟状态栏已经上色了。(fitSystemWindows为true时候,系统UI会占据填充属于他自己的屏幕高度,false时候为使得整个Activity占据屏幕)

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
        {      
            ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);

            View statusBarView = new View(activity);
            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    getStatusBarHeight(activity));//获得高和等宽的布局属性
            statusBarView.setBackgroundColor(int color);//设置需要的颜色作为背景填充
            contentView.addView(statusBarView, lp);
        }

    }
 public static int getStatusBarHeight(Context context)
    {
        int result = 0;
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0)
        {
            result = context.getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }//这里参考hongyang的代码
  • 状态栏颜色与头布局颜色相同适配(类似QQ)
    设置状态栏为透明,让头布局侵入状态栏高度,fitSystemWindows==false默认也为false,设置第一个布局的paddingtop为状态栏高度即可实现这个效果。比如toolbar或者一些自定义的title,(padding为元素边框与元素内容之间的空间距离)
    Android状态栏适配源码解析。_第1张图片
    可以看到这里我们设置Textview为头布局,已经侵入状态栏,如果我们设置一个panddingtop就不是OK了!

参考

http://blog.csdn.net/lmj623565791/article/details/48649563/
http://blog.csdn.net/guolin_blog/article/details/51763825


如果看到这一步:相信我们能够完全适配各种需求对于我们的状态栏。但是为什么要分这么多版本来适配呢?这里我分源码 !!15,19,22!!,3个版本来跟进源码查看结果如下

  • 各种版本都可以得到getwindow.getdecorview() 得到decorview,(decorview
    为最底层界面) 观察这里View.java的最低版本15也支持setsystemUIvisiblity()。但是为什么4.4才能支持透明呢?跟进

4.4以上

   /** @param visibility  Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
     * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
     * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
     * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE},
     * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}.
     */
    public void setSystemUiVisibility(int visibility) {
        if (visibility != mSystemUiVisibility) {
            mSystemUiVisibility = visibility;
            if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
                mParent.recomputeViewAttributes(this);
            }
        }
    }

4.4以下

 /**
     * @param visibility  Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
     * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.
     */
    public void setSystemUiVisibility(int visibility) {
        if (visibility != mSystemUiVisibility) {
            mSystemUiVisibility = visibility;
            if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
                mParent.recomputeViewAttributes(this);
            }
        }
    }

从这里就可知,这一些SystemUI_flag是4.4之后Android官方才做的适配flags;之前并没有这么多设置沉浸透明相关的系统flag。

  • getwinodw().setStatuBarColor()
    查看3个版本的window实现的实现类phonewindow内部可得只有API大于21才有明确的API能够设置状态栏颜色。低于5.0不能直接通过API设置颜色。
@Override
    public void setStatusBarColor(int color) {
        mStatusBarColor = color;
        mForcedStatusBarColor = true; //用于判断是否需要上色状态栏。
        if (mDecor != null) {          //mDecor也就是Decorview对象。
            mDecor.updateColorViews(null, false /* animate */);
        }
    }

跟进方法
private WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
            WindowManager.LayoutParams attrs = getAttributes();
        //getAttributes()跟进发现就是 WindowManager.LayoutParams();

            int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();

                 //首先得到我们布局属性与系统默认的uivisibility,什么不设置的话起初为getWindowSystemUiVisibility()为0。
             //  这里就算不是0其实也无所谓。因为systemUiVisibility这一类参数都是只占一位的比如  000001。000010。000100。....进行或操作只能是全部增加,!这里其实也就是回到我们4.4版本设置UI透明可以用来设置参数的条件。         
         //。。。。。。。                                           
        //中间一段代码省略,是判断高低端设备对是否使用硬件图像加速处理什么的,
        //。。。。。。。。
updateColorViewInt(mStatusColorViewState, sysUiVisibility, mStatusBarColor,
                        mLastTopInset, animate && !disallowAnimate); 
                     //最后传入我们得到的sysUiVisibility 来更改状态栏颜色
                     //此方法从方法名可知道就是修改颜色的不深究.内部作一些判断颜色是否透明,是否需要隐藏判断,以及具体的颜色处理。
                 //

            //这一个完整的过程也就完成了我们的状态栏修改完成了。
            }

最后贴出几个参数的意义

View.SYSTEM_UI_FLAG_VISIBLE :状态栏和Activity共存,Activity不全屏显示。也就是应用平常的显示画面
View.SYSTEM_UI_FLAG_FULLSCREEN :Activity全屏显示,且状态栏被覆盖掉
.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN :Activity全屏显示,但是状态栏不会被覆盖掉,而是正常显示,只是Activity顶端布 局会被覆盖住
View.SYSTEM_UI_FLAG_LAYOUT_STABLE :
防止状态栏隐藏,保证你使用fitSystemWindows时候,系统UI边界
始终不会变,依然存在可见.即使你隐藏了所有,他依然存在,增加了UI稳定性,迫使确认用户了解如何让UI控件回来。
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY:向内滑动的操作会让系统栏临时显示,并处于半透明的状态。此时没有标签会被清除,系统UI可见性监听器也不会被触发。如果用户没有进行操作,系统栏会在一段时间内自动隐藏。

你可能感兴趣的:(Android)