Android沉浸式状态栏(透明状态栏)最佳实现

2018-12-10 00:57:37

最佳解决方案,在最下面,大家可以看一下,不过貌似这样的话,影响EditText聚焦,会出现异常,待解决

Android沉浸式状态栏(透明状态栏)最佳实现

在Android4.4之前,我们的应用没法改变手机的状态栏颜色,当我们打开应用时,会出现上图中左侧的画面,在屏幕的顶部有一条黑色的状态栏,和应用的风格非常不协调;为了提供更好的界面交互,google在Android4.4以后提供了设置沉浸式状态栏的方法,对于沉浸式状态栏这个名字存在争议,我们不做讨论,实际的效果其实就是透明的状态栏,然后在状态栏的位置显示我们自定义的颜色,通常为应用的actionbar的颜色,或者是将应用的整体的一张图片也占据到状态栏中,如下图所示: 



由于这种透明的状态栏是在Android4.4以后才出现的,所以我们需要为4.4以上的版本做适配,方法有两种,一种是在资源文件(style)中设置,一个是在代码中设置。


在资源文件中设置透明状态栏

首先,我们先在values下的style中加入如下代码:


    <!-- Base application theme. -->

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

        <!-- Customize your theme here. -->

        <item name="colorPrimary">@color/colorPrimary</item>

        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>

        <item name="colorAccent">@color/colorAccent</item>

    </style>


    <style name="AppTheme.Main" parent="AppTheme" />

1

2

3

4

5

6

7

8

9

AppTheme.Main是我们要设置给activity的主题,它应该继承于AppTheme.NoActionBar,然后 

我们在values-v19中加入同样的AppTheme.Main,如下所示:


    <style name="AppTheme.Main" parent="AppTheme.NoActionBar">

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

    </style>

1

2

3

然后运行程序,效果如图所示: 

 

图片中我们发现,虽然我们实现了透明的状态栏,但是上边的文字和状态栏的信息重叠了。为了修复这个问题,我们应该在布局文件的根布局中加入android:fitsSystemWindows=”true” 就可以了,加入后效果如下: 

 

应用的文字和系统显示的文字错开了,这也是我们最终的显示效果


需要注意的几点:


为Android4.4+适配的同时,不要忘了在values的style.xml中加入同名的自定义style,不然4.4以下会报错

不要忘记在布局文件中加入 android:fitsSystemWindows=”true”,不然布局内容会和状态栏内容重叠

在Android5.0中,透明标题的效果和4.4中有所不同,但是实现方法相同,我们可以不必为5.0+单独适配,同时5.0+的版本提供了新的API android:statusBarColor,可以用来单独设置状态栏的颜色,但是这种方法不适用于我们例子中的图片占据状态栏,它适用于纯色的状态栏,并且它应该放到value-v21文件夹中


上边的例子中,我们只设置了一个图片,使其占据了状态栏。但是我们平常见到更多的可能不是这种,而且带actionbar的情况,如下所示: 

 

在上图中,存在一个actionbar,然后状态栏的颜色与其相同,接下来我们来实现这种效果。


style文件不用改变,我们需要在布局文件中加入一个toolbar,代码如下:


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

<LinearLayout

    xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@color/colorAccent"

    android:orientation="vertical"

    tools:context="com.zephyr.musicapp.MainActivity">


        <android.support.v7.widget.Toolbar

            android:id="@+id/toolbar"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:fitsSystemWindows="true"

            android:background="?attr/colorPrimary"

            app:popupTheme="@style/AppTheme.PopupOverlay"/>


</LinearLayout>

然后在activity中

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

在一个LinearLayout中包含了一个toolbar,和第一个例子相比,我们把android:fitsSystemWindows=”true”加在了Toolbar上边,而不是LinearLayout中,如果把android:fitsSystemWindows=”true”放到LinearLayout中,会出现下边的效果: 

 

虽然状态栏透明了,但是颜色却和根布局的颜色相同而不是toolbar,这样显然不行,如果我们把android:fitsSystemWindows=”true”放到toolbar中就可以实现我们的效果,如下图所示: 



在这里,我们还需要特别注意一个地方,那就是在设置toolbar高度的时候,应该设置成wrap_content,不然也没法实现我们的效果,比如我把高度固定为50dp,效果如下: 

 

虽然占据了状态栏,但是toolbar的高度明显不够了,效果很不好。


在Android5.0以后,增加了新的API android:statusBarColor 用于设置状态栏的颜色,同时以前的windowTranslucentStatus也是对它有效的,所以如果想通过新的API设置状态栏颜色的话,首先应该将windowTranslucentStatus设置为false,不然是没有效果的。


以上就是通过资源文件设置透明状态栏的方法。


代码中设置透明状态栏

在代码中设置透明状态栏的方法也很简单,思路就是首先通过 WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS设置当前window为透明状态栏,这样标题栏就可以占据状态栏了,但是会出现布局中的内容和状态栏的内容重叠的问题,为了解决这个问题,我们应该获得状态栏的高度,然后设置标题栏的paddingTop为状态栏的高度,这样就可以实现透明效果的标题栏的,代码如下:


 protected void setImmerseLayout(View view) {// view为标题栏

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

            Window window = getWindow();

            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

            int statusBarHeight = getStatusBarHeight(this.getBaseContext());

            view.setPadding(0, statusBarHeight, 0, 0);

        }

    }


    public 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;

    }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

fitSystemWindows属性: 

官方描述: 

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.


补充: 

当为纯色actionbar的情况下,我们将toolbar的高度设为wrap_content,并且将fitsSystemWindows=“true”参数设置到了toolbar上,这样虽然实现了4.4版本的沉浸效果,但是却不能有效的适配5.0及以上的版本,所以做出以上修改。 

在4.4版本上: 

1. 我们将根布局的背景颜色设置成和toolbar一样的,并且设fitsSystemWindows为true。 

2. toolbar的fitsSystemWindows属性去掉,并且高度设置为?attr/actionBarSize 

3. 在toolbar下增加一个子布局,颜色设置为white,这样就可以在4.4及5.0以上实现带actionbar的沉浸式布局


2017.12.14更新: 

使用纯色actionbar的时候,可以使用容器包裹toolbar,只设置容器 fitsSystemWindows为true。由于fitsSystemWindows属性本质上是给当前控件设置了一个padding,所以我们设置到根布局的话,会导致状态栏是透明的,并且和窗口背景一样,和toolbar背景不同。如果我们设置给toolbar,则会由于padding的存在,导致toolbar的内容下移。所以我们选择使用LinearLayout包裹toolbar,并将toolbar的背景等属性设置在appbarlayout上就可以完美实现效果,代码:


 <LinearLayout

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:background="@color/colorPrimary"

    android:fitsSystemWindows="true"

    android:orientation="vertical">


    <android.support.v7.widget.Toolbar

        android:layout_width="match_parent"

        android:layout_height="?attr/actionBarSize"

        app:title="Login"/>

</LinearLayout>


  • 2019-12-04 10:48:18

    vue 项目资源文件 static 和 assets 不说区别直接使用?

    assets中资源会webpack构建压缩到你代码中,而static文件直接引用。 static 中长存放类包、插件等第三方的文件,assets里放属资源文件比如自己资源图片、css文件、js文件。 引入资源的方式static文件夹可以使用~/static/方式引入, assets文件夹可以使用 ~@/assets 方式引入

  • 2019-12-05 17:01:36

    Vue 结合 Axios 接口超时统一处理

    当网路慢的时候。又或者公司服务器不在内地的时候,接口数据请求不回来超时报错的情况相信大家肯定遇到过的,这里我把我公司项目请求超时的处理方法分享下,希望看过后有帮助。

  • 2019-12-05 17:13:40

    JS模板工具lodash.template的简单用法

    lodash是从underscore分支的一个项目,之前我写了一篇JS模板工具underscore.template的简单用法,lodash跟underscore很相似,这也简单介绍一下lodash的template方法。 先把underscore的文章中用过的代码贴过来,把underscore的js文件换成lodash的js,其他一字不改,然后我们试试:

  • 2019-12-06 10:47:29

    date-fns日期工具的使用方法详解

    isToday() 判断传入日期是否为今天 isYesterday() 判断传入日期是否为昨天 isTomorrow() 判断传入日期是否为 format() 日期格式化 addDays() 获得当前日期之后的日期 addHours() 获得当前时间n小时之后的时间点 addMinutes() 获得当前时间n分钟之后的时间 addMonths() 获得当前月之后n个月的月份 subDays() 获得当前时间之前n天的时间 subHours() 获得当前时间之前n小时的时间 subMinutes() 获得当前时间之前n分钟的时间 subMonths() 获得当前时间之前n个月的时间 differenceInYears() 获得两个时间相差的年份 differenceInWeeks() 获得两个时间相差的周数 differenceInDays() 获得两个时间相差的天数 differenceInHours() 获得两个时间相差的小时数 differenceInMinutes() 获得两个时间相差的分钟数

  • 2019-12-06 10:49:39

    npm 查看源 换源

    npm,cnpm,查看源,切换源,npm config set registry https://registry.npmjs.org

  • 2019-12-06 11:01:31

    npm发布包流程详解 有demo

    npm发布包步骤,以及踩过的坑(见红颜色标准): 1.注册npm账号,并完成Email认证(否则最后一步提交会报Email错误) 2.npm添加用户或登陆:npm adduser 或 npm login

  • 2019-12-06 13:16:18

    vue mixins组件复用的几种方式

    最近在做项目的时候,研究了mixins,此功能有妙处。用的时候有这样一个场景,页面的风格不同,但是执行的方法,和需要的数据非常的相似。我们是否要写两种组件呢?还是保留一个并且然后另个一并兼容另一个呢? 不管以上那种方式都不是很合理,因为组件写成2个,不仅麻烦而且维护麻烦;第二种虽然做了兼容但是页面逻辑造成混乱,必然不清晰;有没有好的方法,有那就是用vue的混合插件mixins。混合在Vue是为了提出相似的数据和功能,使代码易懂,简单、清晰。

  • 2019-12-06 13:26:30

    vue的mixins混入合并规则

    混入minxins:分发vue组件中可复用功能的灵活方式。混入对象可以包含任意组件选项。组件使用混入对象时,所有混入对象的选项将混入该组件本身的选项。