zoukankan      html  css  js  c++  java
  • android状态栏总结

    1. 针对状态栏的操作,只针对4.4kitKat(含)以上的机型,部分国产rom会失效,目前发现的有华为的EMUI
    2. Activity必须是noActionbar主题
    3. 本文基于StatusBarUtils略作修改,感谢作者laobie
    4. 本文源码地址
    相关属性重温
    • FitsSystemWindows
      在使用FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDSFLAG_TRANSLUCENT_STATUS挤占了状态栏的高度的时候,我们的布局文件也跟着顶到了状态栏上。通过FitsSystemWindows,系统会把app布局文件的paddingTop修改成状态栏的高度,达到适配的效果

      false顶到状态栏

    true,paddingTop有一个状态栏高度
    • android.R.id.content
      通过它我们可以在不需要知道ID的情况下,访问当前Activity根节点,一般是ContentFrameLayout类型,通过((ViewGroup)findViewById(R.id.content)).getChildAt(0);可以获取到我们布局xml的根节点

    • getDecorView()
      通过他,我们可以获取到整个Window界面的最顶层View。我们用的很多的findViewById(),就是基于这个DecorView查找里面的子节点的。比如Activity主题是Theme.AppCompat.Light.NoActionBar的组织层级如下,


    noActionbarView层次.png

    为什么嵌套那么深,因为各个层次可能都会有几个ViewStub方便注入,只是我们现在的主题用不到就是空了。

    下面开始实战了,一般我们用的比较多的是透明状态栏、设置状态栏颜色、DrawerLayout盖在状态栏上三种。

    1. 透明状态栏

    这种情况一般用于把图片延伸到状态栏上,图片还分两种

    1. 作为background的全屏大图
    2. 作为ImageView控件存在,一般只占屏幕高度的一部分

    这两种情况下的处理方式还不一样,具体看下文

    /** * 使状态栏透明 */
    private static void transparentStatusBar(Activity activity) {    
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {       
              activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);        
              activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
        } 
         else {       
              activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);   
      }
    }

    上面的代码针对5.0以上或者4.4以上5.0以下的机型,让其状态栏透明、导航栏半透明,效果如下:


    透明状态栏的结果是布局文件顶到了状态栏上


    dump了下节点信息,我们发现布局的paddingTop从(50px状态栏高度)被修改成了0px。从而让图片延伸到了状态栏


    不透明状态栏.png

    透明状态栏.png


    这种情况下,对app布局文件通过设置FitsSystemWindows就可以完成适配了

    /**
     * 获取activity的根节点
     *@param activity
     *@return
     */
    public static ViewGroup getAppRootView(Activity activity) { 
       return (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
    }
    
    /**  
    *将目标View的paddingTop从0设置为状态栏的高度
     */
    private static void setRootViewFitSystemWindow(Activity activity) { 
       ViewGroup rootView = getAppRootView(activity);   
       rootView.setFitsSystemWindows(true);   
       rootView.setClipToPadding(true);
    }

    app内容布局有了padding.png


    注意!!要延伸到状态栏的图片,如果不是根节点的背景图,而是一个ImageView控件,那么就不能设置setFitsSystemWindows了,原因参考上图红框。这种情况下,为了防止顶到状态栏,需要手动在xml里通过paddingTopmarginTop调整标题栏元素位置达到适配。类似下图


    延伸到状态栏的图片是一个ImageView

    2. 状态栏颜色

    设置状态栏颜色的步骤和透明类似,差别在于5.0以下机型无法直接设置状态栏颜色,我们可以模拟一个纯色的View放到状态栏下面间接达到着色效果。放置的父层级我们选择DecorView

    如果发现状态栏颜色设置无效,有可能是布局文件的root节点加了backgroundColor所致

    /**
     * 
    设置状态栏颜色
     *
     * @param activity       需要设置的activity
     * @param color          状态栏颜色值
     * @param statusBarAlpha 状态栏透明度
     */
    public static void setColor(Activity activity, int color, int statusBarAlpha) { 
       if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)     return; 
    
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {  
          activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);       
          activity.getWindow().setStatusBarColor(UIUtils.calcColorWithAlpha(color, statusBarAlpha));   
     } else {        
         activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);     
         ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();        
         insertMockStatusBackgroundView(decorView, color, statusBarAlpha);  
      }    
         setRootViewFitSystemWindow(activity);
    }

    上面的代码判断DecorView下第0个View是不是我们自定义的StatusbarView类型,如果是则设置颜色,否则创建一个纯色控件插入到DecorView内,同时布局内容上间距腾出给纯色控件。

    3. DrawerLayout盖在状态栏上

    DrawerLayout主要有两个子元素1:内容View 2:侧滑栏
    侧滑栏必然要在内容View后面以覆盖前者


    侧滑栏效果


    所以我们要做的有2步

    1. 插入纯色控件到内容View(如果不是LinarLayout需要考虑内容View元素重新排列)
    2. DrawerLayout设置fitSystemWindow=false;以覆盖到状态栏上

    代码如下:

    /** * 为DrawerLayout 布局设置状态栏变色
     * 
    * @param activity       需要设置的activity 
    * @param drawerLayout   DrawerLayout
     * @param color          状态栏颜色值
     * @param statusBarAlpha 状态栏透明度 
    */public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, int color, int statusBarAlpha) { 
       if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {        return;    }  
    
       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().setStatusBarColor(Color.TRANSPARENT);   
       } else {        
         activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 
       }    
         ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);    
         //如果内容view不是LinearLayout,则需要重新排列内容view子元素的内容    
         insertMockStatusBackgroundView(contentLayout, color, statusBarAlpha);    
         drawerLayout.setFitsSystemWindows(false);
    }

    总结:

    上面三个方法,涵盖了app在大部分沉浸场景下的状态。在了解了底层实现后,我们也可以轻松在安卓上实现IOS的沉浸效果了,最低版本4.4 kitkat现在已经非常普及,随着MIUI、FlyME相继都升级到5.0、6.0以上,魅蓝、红米等大批国产中低端机型的都可以体验到这种酷炫的效果了。

  • 相关阅读:
    Leetcode Spiral Matrix
    Leetcode Sqrt(x)
    Leetcode Pow(x,n)
    Leetcode Rotate Image
    Leetcode Multiply Strings
    Leetcode Length of Last Word
    Topcoder SRM 626 DIV2 SumOfPower
    Topcoder SRM 626 DIV2 FixedDiceGameDiv2
    Leetcode Largest Rectangle in Histogram
    Leetcode Set Matrix Zeroes
  • 原文地址:https://www.cnblogs.com/ldq2016/p/6671889.html
Copyright © 2011-2022 走看看