Android 沉浸式状态栏总结

在 Android4.4 之后,Android Window支持了一些新的属性,其中有两个是这样的 .

WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
正如它们的变量名的意思,使用这两个属性,可以使得状态栏和导航栏变为透明,导航栏指的就是Android下方的三大按键,当然只使用第一个属性也可以达到今天所要完成的效果。下面的示例代码将使状态栏和导航栏变得透明

@Override
protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     initWindow();
}
@TargetApi(19)
private void initWindow(){
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);   
  }

或者对主题设置(注意对 values 资源的限定,仅用于 API19 及以上): <item name="android:windowTranslucentNavigation">true</item> <item name="android:windowTranslucentStatus">true</item>

在使用沉浸式主题是,布局会往上移,如图

Android 沉浸式状态栏总结_第1张图片

Flyme4.2 Android4.4.4上运行效果

这个问题也很好解决,有2个解决方案

1.在 style theme 添加

<item name="android:fitsSystemWindows">true</item> 有bug,布局中的Padding会失效
布局时是否考虑给系统窗口留出空间,true为留出空间(如 Status Bar and App bar)

2.计算状态栏的高度,为每个RootView设置Padding (推荐使用这个方法,因为fitsSystemWindows会产生比较多的问题,如Toast弹出位置也会往上移,最外层Padding也会失效)

 public int getStatusBarHeight() {
 int result = 0;
 int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
 if (resourceId > 0) {
     result = getResources().getDimensionPixelSize(resourceId);
 }
     return result;
 }

之后我们再运行,却又发现,状态栏的位置出来了,但是。。。

Android 沉浸式状态栏总结_第2张图片
Flyme4.2 Android4.4.4上运行效果

实际上,状态栏已经透明了,只是状态栏底下没有颜色呀!
Google 了之后在 Github 找到了一个开源项目 SystemBarTint ,代码就变成下面这个样子:

   private SystemBarTintManager tintManager;
   @TargetApi(19)
   private void initWindow(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            tintManager = new SystemBarTintManager(this);
            tintManager.setStatusBarTintColor(getColor(R.color.app_main_color));
            tintManager.setStatusBarTintEnabled(true);
        }
    }

运行之后,发现运行效果跟第一张图一样,达到我们想要的效果了。

跟踪进去查看 SystemBarTint 的源代码,会发现 SystemBarTintManager 的构造方法里面除了获取 ActionBar 的高度等等这些配置之外,还有一个重要的方法 setupStatusBarView

    @TargetApi(19)
    public SystemBarTintManager(Activity activity) {
        Window win = activity.getWindow();
        ViewGroup decorViewGroup = (ViewGroup) win.getDecorView();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        //省去部分代码...
        if (mStatusBarAvailable) {
            setupStatusBarView(activity, decorViewGroup);
        }
        if (mNavBarAvailable) {
            setupNavBarView(activity, decorViewGroup);
        }
    }

于是接着查看 setupStatusBarView 的代码

private void setupStatusBarView(Context context, ViewGroup decorViewGroup) {
        mStatusBarTintView = new View(context);
        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight());
        params.gravity = Gravity.TOP;
        if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) {
            params.rightMargin = mConfig.getNavigationBarWidth();
        }
        mStatusBarTintView.setLayoutParams(params);
        mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR);
        mStatusBarTintView.setVisibility(View.GONE);
        decorViewGroup.addView(mStatusBarTintView);
    }

可以发现这个开源项目能够解决我们的问题的原因在这,就是往 DecorView 加入一个 View, 而在代码中我们将这个 View 的背景设置成 ActionBar 一样的颜色,所以就达到了沉浸式的效果。到这里,基本也就分析完成了。

附上源代码地址: Github 源代码 .

--------------------------------------------------------------------
上面可以解决大部分的Android 系统
但是。。。沉浸式状态栏是有坑的
  •  一个已知的BUG

沉浸式状态栏的一个BUG, 导致在软键盘弹出后页面没有resize,内容被键盘遮住,adjustPan不起作用,如写说说、写日志这些界面。直接在需要relayout的子view上添加fitsSystemWindows属性。
  • 状态栏高度不一致
部分rom(如miui和Flyme等)修改了状态栏高度,miui改高了,而meizu上的flyme则改矮了,所以不能直接写作25dp。在CustomTitleBar组件中通过重写getPaddingTop方法来兼容所有状态栏高度。

  • 很多rom把渐变阴影给去了(CM、miui、Flyme OS等等)

大部分应用了沉浸式状态栏的应用都没有考虑到这点,如腾讯地图,导致在那些rom上打开应用后状态栏一片白乎乎的看不清

尽管google的原生4.4 rom中,在设置了沉浸式状态栏后,会对状态栏区域加上一条渐变的背景,来防止亮色导致状态栏图标/字看不清,但实际应用中发现其实很多rom把渐变阴影给去了,所以在状态栏组件中,加上了绘制阴影的选项(包括5.0半透明黑条和4.4渐变阴影两种选项),会在4.4机器开启了沉浸式状态栏时,绘制阴影。

小米 的MIUI6解决方案 :  MIUI 6 沉浸式状态栏调用方法
  • fitsSystemWindows 设置为true,Toast文本显示偏上方什么鬼?
Android 沉浸式状态栏总结_第3张图片
  1. 不要设置Activity的theme的fitsSystemWindows为true 
  2. 或者使用getApplicationContext()


相关链接:

http://www.jianshu.com/p/f8374d6267ef

http://blog.csdn.net/marktheone/article/details/46663035

http://codersimple.github.io/android/2015/05/15/immersive-theme-for-android.html


点击下载我的Demo源码


下面了解各种状态栏的定义

---------------------------------------------------------------------------------------------------


状态栏变色龙


状态栏变色龙是一款以Xposed为框架的插件,它可以将状态栏的颜色和正在运行的应用程序的颜色调整为一体,实现更好的视觉效果。
  1. 沉浸式:全屏模式,通知栏隐藏,即全屏,部分应用打开时会出现
  2. 沉浸式状态栏
  3. 变色龙式状态栏:将状态栏本身的背景全透明化,同时改变应用窗口顶部的颜色。这样能在切换应用窗口时,完成同步变色,并且将色彩一体感做得比原生系统更彻底。既保证顶栏应用图标和文字清晰显示,又将顶栏的颜色与下部的颜色无缝连接起来。将动静态之间的效果调整恰当,让整体的视觉显得流畅。
  4. 透明通知栏:MIUI V5这类的老系统,虽然是Android4.2,但是桌面还是能透明的。
在动态切换上,原生沉浸式优于变色龙。变色龙改变的是状态栏本身的背景颜色,而Android的状态栏是一个单独的窗口,无法和应用窗口的动画做到完全同步,因此变色龙状态栏本身背景颜色变化的时候,无法做到整块颜色的同步切换,会出现和应用窗口内颜色衔接不连贯的情况。

在静态画面展示上,变色龙却优于原生沉浸式。变色龙在静态画面中的颜色是一体化的,而原生沉浸式的顶栏的会增加一层阴影,用来突出状态栏处白色的文字和图标,但这使得原生沉浸式在静态画面中呈现出割裂感,带来的视觉体验不是很好。

沉浸式状态栏示例:
Android 沉浸式状态栏总结_第4张图片
变色龙通知栏示例


Android 沉浸式状态栏总结_第5张图片


透明状态栏示例:







你可能感兴趣的:(Android 沉浸式状态栏总结)