Android 状态栏操做,你想知道的都在这里了

一直以来,iOS 设备上状态栏背景色和图标文字颜色的灵活可变性始终受到设计人员的青睐,有意地恰当地融入到 App 的各类界面设计当中,更好地提高用户体验。php

因为系统的限制,在老版本的安卓系统中,Android App 没法作到这些,产生一些设计上的遗憾。幸运的是,自 4.4 版本(API 19)之后,Android 系统开始支持状态栏的定制,并被归入 Android 设计规范当中,Android App 在设计上迈出了重要的一步。html

“沉浸式状态栏” VS “透明状态栏”?


通常来讲,Android 默认的状态栏样式表现为黑底白字,若是咱们应用的标题栏背景色也为黑色,那就能与状态栏很好地衔接在一块儿,体验极佳。反之,若是为其余的颜色,整个界面的呈现效果就会大打折扣。java

幸运的是,Android 4.4 版本开始,系统提供了相应的 API,支持状态栏全透明化,界面 Content View 能够延伸到状态栏上,填充状态栏背景色。而在 Android 5.0 版本开始,系统在此基础上作了进一步优化和规范,可以实现动态改变状态栏背景色,在透明度上默认呈现为半透明化,可定制化程度更高。android

在此基础上,最终要作到咱们的应用呈如今 Android 各个系统版本上的效果如图所示:git

Status Bar

关于 Android 4.4 版本开始的状态栏变化,许多人喜欢称之为“沉浸式状态栏”,但从系统提供的 API 命名上能够看出,核心词汇为 “Translucent”,故准确来说,这种效果又应该称之为“透明状态栏”。知乎上对于这两种叫法也很有争议,具体内容可参考话题:为何在国内会有不少用户把「透明栏」(Translucent Bars)称做 「沉浸式顶栏」?。可能对于设计师而言,沉浸式仍是透明式的称呼有所区别,但对于广大开发者而言,无足轻重,咱们所关注的应该是如何实现这种效果,并可以很好的兼容到各个版本中。github

相关 API 介绍


通常来讲,目前在 Android 项目中咱们都会使用 Toolbar 替代 ActionBar 来实现导航栏,除此以外,要实现透明状态栏效果,还须要了解两个相关 API,下面逐一介绍一下:windows

一:api

<item name="android:windowTranslucentStatus">true</item>复制代码

也能够在代码中实现(听说,在代码中实现兼容性更好,style 资源中设置的方式在某些国产手机厂商定制的系统中存在一些问题):微信

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
    local LayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
}复制代码

顾名思义,该属性可以实现透明状态栏效果,是在 Android 4.4 版本引入的,也就是兼容至 API 19 及以上版本。使用该属性设置主题后,内容布局向上延伸至状态栏,而且在不一样版本的系统中呈现效果也有所区别,如图所示:app

显然,在 API 19 及更高版本上,Toolbar 内容延伸至状态栏上去了,出现重叠问题,此时,就须要使用到另外一个属性了。

二:

android:fitsSystemWindows="true"

Boolean internal attribute to adjust view layout based on system windows such as the status bar. If true, adjusts the padding of this view to leave space for the system windows. Will only take effect if this view is in a non-embedded activity.

用在 layout 布局文件中。官方文档给出了很明确的介绍,大体是说可以将使用该属性的视图与系统窗口(如状态栏)保持必定的 padding 间距。因此若是咱们在 toolbar 中设置了该属性,就可以解决 <item name="android:windowTranslucentStatus">true</item> 配置带来的视图延伸问题,使呈现效果达到文章开始所示图中的效果。

使用案例分析


res/values/styles 文件中定义基础主题样式:

<style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar"/> <style name="AppTheme" parent="BaseTheme"> </style>复制代码

res/values-v19/styles 文件中定义兼容主题样式:

<style name="AppTheme" parent="BaseTheme"> <item name="android:windowTranslucentStatus">true</item> </style>复制代码

而后在 AndroidManifest.xml 文件中使用全局主题样式:

<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="Samples" android:supportsRtl="true" android:name=".MyApplication" android:theme="@style/AppTheme">

        ......复制代码

新建一个 layout 布局文件,单独定义 toolbar 内容,在应用中的其余 Activity 界面布局中使用 include 标签潜入引用:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/tb_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?actionBarSize" android:background="@color/colorPrimary" android:fitsSystemWindows="true" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:title="@string/app_name" app:titleTextColor="@android:color/white">

</android.support.v7.widget.Toolbar>复制代码

这里使用 android:fitsSystemWindows="true" 属性解决内容试图向上延伸的问题。实际上,也可使用 android:paddingTop="@dimen/toolbar_padding_top" 的方式解决,toolbar_padding_top 间距为状态栏高度,在大多数机器上状态栏高度为 25dp,固然也能够经过代码动态获取状态栏高度并设置到 Toolbar 的 paddingTop 属性上。须要注意的是,这里要作兼容判断,好比在 res/values/dimens.xml 中定义toolbar_padding_top 高度为 0dp,在 res/values-v19/dimens.xml 中为 25dp,确保兼容 Android 4.4 如下版本。

基本上,作到这些就可以实现文章开头处图中的效果。值得注意的是,有时候若是想在 Android 5.0 及以上版本的系统中也作到全透明效果,或者说状态栏与导航栏的颜色一致,还能够作进一步兼容处理,毕竟自 5.0 版本开始,系统对于状态栏背景色的定制提供了更好的 API。如 res/values-v21/styles.xml 中定义:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="AppTheme" parent="BaseTheme"> <item name="android:colorPrimary">@color/colorPrimary</item> <item name="android:colorPrimaryDark">@color/colorPrimary</item> <item name="android:colorAccent">@color/colorAccent</item> </style>

</resources>复制代码

说明一点,使用这种处理方式后,5.0 系统中应用的状态栏背景色可随意定制,同时与使用 <item name="android:windowTranslucentStatus">true</item> 样式有所不一样的是,该处理方式不会引发内容视图的向上延伸,因此不须要在 layout 布局文件中额外添加 android:fitsSystemWindows="true" 属性。固然,添加了也无所谓,毕竟还要兼容 4.4 到 5.0 之间的版本。

状态栏白底黑字


前面咱们说过,虽说 4.4 版本开始,能够实现透明状态栏效果,也就是能够经过各类手段实现修改状态栏背景色,可是状态栏图标和文字的颜色默认为白色,这个是没法像 iOS 系统那样,根据应用的总体色调动态修改。若是刚好 Toolbar 的背景色为白色,为了保持一致,将状态栏背景色调为白色的话,就会与状态栏的白色内容发生冲突,致使其内容没法凸显,这个体验确定没法被用户接受。

因此,碰见这种 Toolbar 或者说导航栏背景色为白色的状况,通常有两种处理方式:第一种,不修改状态栏背景色,一般默认为黑色背景白色内容;第二种,修改状态栏背景色为淡黑色,这样既能显示状态栏内容,又能与白色导航栏弱显衔接,好比支付宝 App 就是这么作的:

Alipay Status Bar

像上图这种处理方式较黑色状态栏来讲,相对缓和一些,那能不能作到修改状态栏内容的颜色呢,好比白底黑字?你们知道,Android 系统是开源的,国内的各家手机厂商都作了一些本身的定制,像部分厂商定制的系统就提供了相应的 API 供开发人员作适配工做。好比,部分厂商就提供了相应的 API 来修改状态栏内容颜色,实现状态栏白底黑字效果,如图:

具体作法就是,在代码中判断系统类型,与提供修改状态内容颜色的系统匹配,使用其特定的 API 操做便可。目前开放这种定制 API 的系统已知有 MIUI 和 Flyme 系统,具体实现代码可参考:

其实,在 Android 6.0(API 23)及更高的版本上,系统也开始提供了对应的 API 来实现浅色调背景的状态栏效果,可将状态栏图标和文字内容改成黑色样式,实现方式为:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            getWindow().getDecorView().setSystemUiVisibility(
                    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }复制代码

可是不知国内厂商在定制系统时是否对此有作处理,可否兼容这个 API ?不过,貌似微博 App 是这么作的,你们感兴趣地不妨一试。

注意事项


除了上述 Toolbar 与 状态栏在背景色上的衔接,App 中常见还有这样一种设计,以微博我的主页为例,如图所示:

页面顶部的图片内容延伸至状态栏中,这种作法其实就是单独使用 <item name="android:windowTranslucentStatus">true</item> 样式,不在 layout 布局文件中添加 android:fitsSystemWindows="true" 属性便可。

还有一点,一般咱们会在资源文件中定义不一样版本的主题样式,再在 <application> 标签中统一设置,而后全部的 Activity 都能使用这个主题样式。但存在这样一种状况,Activity 由不一样的 Fragment 组成,而后不一样 Fragment 在状态栏的呈现上有所不一样,好比有的 Fragment 顶部使用 Toolbar 与状态栏衔接,有的顶部直接使用图片延伸至状态栏上甚至不会用到 Toolbar,如图所示:

因为 Fragment 是没法像 Activity 那样在 AndroidManifest.xml 中单独设置主题样式的,因此这里能够这样作:宿主 Activity 仍是使用透明样式,以知足图片延伸的 Fragment 页面效果,其余使用 Toolbar 的 Fragment,在其 Layout 布局文件顶部单独定义一个 View,让其延伸至状态栏,而后在代码中根据不一样版本系统设置其高度,4.4 版本如下设置该 View 高度为0,4.4 及以上版本设置为设备状态栏高度,经过代码获取状态高度的方式以下:

/** * 获取状态栏高度 * @param activity * @return */
    public static int getStatusBarHeight(Activity activity){
        Rect rect = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        return rect.top==0 ? 60 : rect.top;
    }复制代码

最后再补充一点,你们知道,长按 Toolbar 中 Menu Item 时会显示一个 Toast 提示,内容来自 Item 定义时对应的 title 属性,一般显示如图所示:

可是,若是你误将 fitsSystemWindows 属性设置在了 style 样式文件中,好比:

<style name="BaseTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:fitsSystemWindows">true</item> </style>复制代码

将会致使下图效果:

可见,Menu Options Item 长按时弹出的 Toast 样式没了内容间距,显然很丑。因此,记得将该属性设置在正确的布局文件中,不要设置成全局的。

相关拓展


以上即是有关 Android 4.4 开始的状态栏背景色相关知识,能够看出 4.4 、5.0 、6.0 版本做为三个分水岭,根据须要作好相关适配工做便可。还有一种经过 setSystemUiVisibility() 方法设置状态栏的方式,还能实现状态栏的显示与隐藏交互效果,具体可参考这篇文章:

GitHub 上对于 Android 4.4 版本开始的状态栏背景色的处理有一个开源库,感兴趣地朋友也可借鉴参考一番,地址以下:

有关 Toolbar 替换 ActionBar 的使用,能够我以前总结的一篇文章,地址为:

欢迎关注我


本文由 亦枫 创做并首发于 亦枫的我的博客 ,同步受权微信公众号:技术鸟(NiaoTech),欢迎关注。