美文网首页DoAndroid
android全屏透明状态栏的坑

android全屏透明状态栏的坑

作者: 我想04 | 来源:发表于2017-12-17 23:54 被阅读0次

零、摘要

Android全屏透明状态栏的文章已经有不少了,也有开源的库甚至,本文着重讲具体实施背后遇到的那些坑。

一、为什么

现有很多app在Android机器上状态栏的体验并不好,有一道灰色的条。比如手机QQ在7.0 vivo上的效果:


图1.1

我们期望的效果是:

  1. 全屏,app界面的布局延伸到状态栏
  2. 没有顶部的阴影
  3. 状态栏背景色为透明或者跟随app界面颜色
  4. 状态栏字体和icon颜色可以根据界面颜色深浅设置为浅或深,以避免都为浅色或深色而看不见状态栏字体和icon。
    如下图所示效果:


    图1.2

    图中左边状态栏背景是透明,字体是浅色,右边状态栏背景是白色,字体是深色。

二、怎么做

为了达到一中所说的1,2,3和4的效果,先看下Android在api上的支持。

2.1 Android4.4

可以实现状态栏背景色透明或其它颜色,但是做不到效果中的4。
实现步骤:

  1. 通过配置values-19文件夹下的style属性
<item name="android:windowTranslucentStatus">true</item>

或者activity里设置

getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
  1. 状态栏透明后,可以再自己定义一个状态栏高度的view,设置其颜色就相当于设置状态栏背景色了。可以参考其它状态栏的文章,不再赘述。
    这样得到的效果:


    图2.1

然而,试了几款机器,发现并不是所有机型都能达到这个效果,比如vivo的机器上就不行,没有全屏:


图2.2

看效果是全屏的flag没起作用,因为官方文档说,设置了WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS flag后,会自动设置另外两个属性:

When this flag is enabled for a window, it automatically sets the system UI visibility flags SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.

手动把这两个属性设置后,布局倒是延伸到状态栏了,不过状态栏也不见直接隐藏了,有兴趣的可以研究下vivo的4.4机器上能不能做到。

再比如三星机器上,系统会默认给系统状态栏加点阴影:


图2.3

再比如oppo r7的coloros 2.1系统上能达到理想效果,也有oppo r7效果不行,状态栏是黑色,可能和coloros的版本有关系吧。

注:如果在android高版本设置了4.4的这个属性,通常会是开篇说的手q那种效果。

2.2 Android5.0和Android5.1

可以直接实现状态栏背景颜色,不用像4.4上需要自己去搞自定义view,当然也可以给状态栏设置一个透明颜色,然后继续用自定义view的方案也是没问题的。但是和4.4一样,没法改变状态栏字体和icon颜色。
按照官方文档:

Sets the color of the status bar to color. For this to take effect, the window must be drawing the system bar backgrounds with FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS and FLAG_TRANSLUCENT_STATUS must not be set.
If color is not opaque, consider setting SYSTEM_UI_FLAG_LAYOUT_STABLE and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN.

代码如下:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getWindow().setStatusBarColor(getResources().getColor(android.R.color.holo_red_light));

如果不是不透明,也就是有透明度的,把这两个也设置上:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

具体效果和机型适配不再测试。。。

2.3 Android6.0及以上

到了这里,终于可以完全实现我们要的效果了。因为Api23增加了一个属性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,可以设置状态栏字体和icon是深颜色还是浅颜色。设置状态栏背景色的api还是和Android5.0上一样。代码差不多就这样:

if(Build.VERSION.SDK_INT >= LOLLIPOP) {
            int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 
            getWindow().setStatusBarColor(Color.TRANSPARENT); 
            if(Build.VERSION.SDK_INT >= M) {
                uiFlags = setStatusBarDarkFont(uiFlags);
            }
             getWindow().getDecorView().setSystemUiVisibility(uiFlags);
        }

private int setStatusBarDarkFont(int uiFlags) {
        if (isSystemSetDarkFontSupport() && mFontDarkMode) {
            return uiFlags | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
        } else {
            return uiFlags;
        }
    }

这样设置后我们的app界面就从状态栏顶部开始布局了,根据需要有些界面可以直接在状态栏的位置就显示,有些可能需要从状态栏下沿才开始显示,具体效果可参见图1.2中的左和右,针对后者,我们还可以像4.4一样,自己搞一个假的view占位,也可以用其它不少的方法,具体可参见这篇文章:
http://www.jianshu.com/p/2a884e211a62
本文建议还是自己搞一个假的view占位,原因后面会说。
这样就万事大吉了?如果是的话那就不叫Android了,接下来说说那些坑吧,主要针对Android6.0及以上的系统。

三、坑

3.1 闪的问题

通过2.3中的api设置后,发现很多机器在切换activity时,状态栏会闪一下,解决方案,需要在Activity的style属性里添加:

        <item name="android:windowIsTranslucent">true</item>

可以在values-v23文件夹下加。不过加了这个会有些影响:

  1. 对activity生命周期的影响,Activity A上启动了一个加上此属性的Activity B,A不会走onStop,当B销毁时,A不会走onStart。如果基类Activity或某些Activity在onStart里有些特殊逻辑处理需要注意下。
  2. 对transition动画可能会有影响,比如我遇到的是通过ActivityOptionsCompat.makeSceneTransitionAnimation做动画的界面,在onBackPressed activity时会黑屏一下,我是在onBackPressed直接finish掉不做动画,不调super.onBackPressed。

3.2 DialogFragment问题

全屏DialogFragment时,发现状态栏顶部还是和开篇说的QQ那样的效果,代码里怎么调都还是那结果,差点放弃。。最后发现,在布局里调用就好了,原因就懒得去找了。

<item name="android:windowTranslucentStatus">false</item>
        <item name="android:statusBarColor">@color/thirtyalphablack</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>

再特别提一句,meizu flyme上不要通过这种方式,否则状态栏和布局之间会有一条灰线,不过魅族不加这些参数全屏DialogFragment也显示正常。

3.3 左右滑动问题

2.3中说到,尽量自己搞个占位的view来让需要的界面从状态栏下面开始展示,这样一方面是好控制,另一方面是遇到,如果是通过setStatusBarColor或者设置ContentView的padding来的话,左右滑动时,状态栏不会跟着走,这样的效果:


1513524906862.jpg

这个问题如果不通过占位方式的话,感觉应该也可以解决,有兴趣的可以研究下。

3.4 特例品牌魅族

魅族从FlymeOS4就开始提供了设置状态字体深色或浅色的api了,这里建议判断下是否大于等于Flyme OS4,是的话使用其自己的api,使用系统的反而有问题,好像会导致切换字体颜色时闪。

3.5 特例品牌小米

小米也一样,很早就搞了自己的私有API来设置状态栏字体颜色深浅,不过在其开发版7.7.13后又恢复到原生api了,私有API没有了效果。但是miui的开发版和发布版并没有明确的对应关系,所以系统的和小米的都得调,不过根据MIUI9的发布日志,可以推测MIUI9以后都是开发版7.7.13之后了,所以可以判断下如果是大于等于miui6小于miui9之间,两种api都调,大于等于miui9的话则只需调用系统的。参考链接:
http://www.miui.com/thread-8946673-1-1.html
摘要:

大家好,在本周开发版公测后,MIUI 对状态栏字符颜色的逻辑做了一次调整:
1. 在 Android 6.0 以前,Android 没有方法可以实现「状态栏黑色字符」效果,因此 MIUI 自己做了一个接口;
2. 在 Android 6.0 及以上版本,Android 提供了标准的方法实现「状态栏黑色字符」效果,但这个方法和 MIUI 的方法产生了冲突,
所以当开发者使用 Android 标准方法时,没有出现预期的效果,这给很多开发者都造成了困扰,尤其是海外开发者。
基于以上背景,我们决定兼容 Android 的方法,舍弃 MIUI 的自己的实现方法。这个改动将会在 7.7.13 公测开发版开始生效(内测版本已生效),
之后随稳定版外发。非常抱歉给各位带来麻烦,但长远来看,兼容 Android 的标准,减少了开发者的适配成本,对整个 Android 生态也更为有利。

http://www.miui.com/thread-8944996-1-1.html
摘要

MIUI 9 第一个内测版本已于7月27日上午10:00进行推送。首批适配机型:小米手机6、红米Note 4X-高通版(其他机型将分批陆续进行内测)。
已申请 MIUI 9 内测报名并通过审核的米粉,请注意阅读以下升级方式:
 1. 小米手机6:7.7.20开发版/体验版米粉,可通过 OTA 更新增量包方式,升级至 MIUI 9。
 2. 红米Note 4X-高通版:7.7.13开发版、7.7.22体验版,可通过 OTA 更新增量包方式,升级至 MIUI 9。

3.6 全屏切换问题
切换到全屏时,如果隐藏状态栏了,那么这种情况下就不要调用上述函数。

四、总结

  1. 上述实现可以放基类Activity的onResume里,然后添加些可以被子类重写的函数,比如状态栏字体颜色深浅,界面展示是可以和状态栏重合还是得从状态栏下沿开始等。
  2. Android真是坑,API好难用!

五、感谢

最感谢的是这篇文章及其代码了:
http://www.jianshu.com/p/2a884e211a62

相关文章

网友评论

    本文标题:android全屏透明状态栏的坑

    本文链接:https://www.haomeiwen.com/subject/enkswxtx.html