美文网首页Android区别之路.安卓UI
Android 沉浸式详解以及各个版本差异问题

Android 沉浸式详解以及各个版本差异问题

作者: __素颜__ | 来源:发表于2019-03-12 19:09 被阅读448次

    一沉浸式样式

    首先,我要实现的最终效果是这样的,即在Android4.4及以上版本系统上,统一显示为如下效果:


    image.png

    沉浸式状态栏,就是指上面的效果,状态栏和Toolbar的颜色保持一致,融为一体的效果。

    二.Andrroid 各个版本沉浸式区别

    先来了解Android 各个版本号、别称以及市场占用比例和对沉浸式效果的影响。


    image.png
    1.Android4.4 kitkat 奇巧版本(可改透明)

    Android4.4以前的版本,状态栏的颜色都是黑色的,而且无法修改。
    Android4.4开始,新增了设置状态栏背景色透明的属性。

    2.Android5.0 lollipop 棒棒糖版本(可改背景颜色)

    Android5.0这种效果是状态栏的颜色上面覆盖了一层半透明的颜色。
    Android5.0开始,系统又新增了设置状态栏颜色值的属性和接口。

    3.Android6.0 marshmallow 棉花糖版本(可改字体颜色)

    Android6.0新增了设置状态栏里内容色调的属性和接口,可以把状态栏的文字色调由亮色改为暗色(亮色是白色,暗色是黑色)。

    还有后面的牛轧糖版本,奥利奥版本,做沉浸式效果就没有什么问题了。

    三.各版本具体差异

    Android4.4

    Android4.4以前的版本,状态栏的颜色都是黑色的,而且无法修改;但一般APP的Toolbar都不会设置为黑色,于是,两者有十分明显的颜色区分,各自占有不同的区域,填充不同的颜色。简单的说,Android4.4以前的版本是无法做到沉浸式的效果的(做系统开发的除外),所以如果想要统一风格的话,可以设置APP最小支持的版本为4.4,如果不行,就没办法了,只能4.4以前一个样式,4.4及以后一个样式。

    Android4.4开始,新增了设置状态栏背景色透明的属性,新增的属性是这两个:

    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS 
    WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
    

    这两个属性分别设置状态栏和导航栏背景色为全透明。(这里只讨论状态栏,只设置上面一个属性就行,导航栏的类似)

    实现方法很简单,在Activity初始化时,调用以下代码:

    // Translucent status bar
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    }
    

    由于是代码设置,所以无法通过xml预览到想要的结果,一定要在4.4真机上运行才能看到效果。

    到这里可能存在两个问题:

    1. Toolbar把状态栏的空间占用了,挤到一起。

    2. 状态栏和Toolbar并没有完全融为一体,而是从上到下,由黑色渐变到Toolbar的颜色。

    第一个现象是必现的,解决方法是在Toolbar的布局文件里加上一个属性:

    android:fitsSystemWindows="true"
    

    这个属性必须加在Toolbar或者Toolbar的父控件上,也就是,如果Toolbar直接写在Activity的布局文件里,则在Toolbar上加这个属性,如果Toolbar是include到Activity的布局文件里,则可以加到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:orientation="vertical"
        tools:context="com.chengsy.immersive.MainActivity">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:fitsSystemWindows="true"
            app:title="@string/app_name"
            app:titleTextColor="#FFFFFF">
    
        </android.support.v7.widget.Toolbar>
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="Hello World!" />
    
    </LinearLayout>
    
    
    

    上面这种情况,如果写到linearlayout中,就会出现问题,StatusBar的背景色跟整个窗口的背景色一样(或者跟桌面颜色一样),而不是和Toolbar的颜色一样。效果如下:


    image.png

    第二个现象根据不同的系统厂商,效果不一样,也就是不同的手机厂商做的不一样,没办法,但是不是太影响沉浸式的效果。
    效果如下:


    image.png
    总结一下,4.4版本,需要设置两个地方来实现沉浸式效果:

    1.设置状态栏透明
    2.设置Toolbar的fitsSystemWindows属性为true

    Android5.0

    先看看通过上面的设置,程序运行在Android5.0的设备上是什么效果:
    可能的效果也有两个,一个是我们想要的效果,沉浸式,不再配图了,另一个是这样的:

    image.png

    这种效果是状态栏的颜色上面覆盖了一层半透明的颜色,不是全透明。当然,原因你懂得,不同厂商系统设计师的idea是不一样的,
    但是这里说一下,谷歌官方的Mertial Design的设计规范是如上图所示,并不是沉浸式的效果,但国内的APP现在普遍比较
    喜欢沉浸式的效果。
    那么如果要统一5.0的效果跟4.4的效果保持一致,全部都是沉浸式该怎么办???
    这么办---
    首先,Android5.0开始,系统又新增了设置状态栏颜色值的属性和接口:

    WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
    

    通过这个属性来设置设置状态栏的背景色,来实现两者融为一体的效果,代码实现如下:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getWindow().setStatusBarColor(Color.TRANSPARENT);// SDK21
    }
    

    原理很简单,首先要清空之前设置的FLAG_TRANSLUCENT_STATUS属性,然后添加修改状态栏背景色的属性FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,最后给状态栏设置为全透明。
    这里有坑,有的5.x的设备,如果调用这句代码getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);状态栏会变黑色,这时候需要去掉这句。但是去掉这句代码,在6.0+系统上半透明的状态栏又出现了。所以处理方法是判断如果是某种特殊的系统,
    不调用上述代码。

    Android6.0

    对于Android6.0及以后的系统,对这方面的支持就已经很完善和统一了,通过4.4设置的FLAG_TRANSLUCENT_STATUS属性和fitsSystemWindows属性就可以达到想要的效果了,不需要做特殊处理,版本内暂时不存在机型之间的差异。

    但是6.0也不是完全没新的东西(指的是状态栏这一块内容),6.0新增了设置状态栏里内容色调的属性和接口,通过设置如下属性,可以把状态栏的文字色调由亮色改为暗色,亮色是白色,暗色是黑色:

    getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
    

    看名字感觉跟我的描素不一样啊,其实,这个属性是把状态栏标记为亮色调,从而,系统会自动把状态栏的文字内容变为暗色调,如果你的APP的Toolbar颜色是亮色的,再配上亮色的内容就会不明显,上面的代码可以解决这个问题,自动将状态栏的内容改为暗色调。

    三.其他问题

    输入框的兼容问题

    如果想要页面底部的输入框可以被键盘顶起来,并且不影响页面的沉浸式效果,需要做两点:

     - AndroidManifest.xml文件配置键盘属性:android:windowSoftInputMode="adjustResize"
     - Activity页面根布局设置 android:fitsSystemWindows="true" 属性
    

    布局代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout 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:fitsSystemWindows="true"
        android:orientation="vertical"
        tools:context="com.chengsy.immersive.MainActivity">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:fitsSystemWindows="true"
            app:title="@string/app_name"
            app:titleTextColor="#FFFFFF">
    
        </android.support.v7.widget.Toolbar>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/toolbar"
            android:gravity="bottom">
    
            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Hello World!" />
        </LinearLayout>
    
    </RelativeLayout>
    
    
    

    通过上面的处理,状态栏的颜色不对了,变成了白色或者桌面的背景色,问题又来了。解决方法的原理就是给状态栏填充上颜色,但是,给状态栏修改颜色的属性和接口在5.0才出现,[4.4--5.0)版本的怎么办?用SystemBarTintManager,Github上的开源库,解决眼前的问题。使用很简单,引用这个库:

     compile 'com.readystatesoftware.systembartint:systembartint:1.0.3'
    

    代码中设置:

    private SystemBarTintManager tintManager;
     
     tintManager = new SystemBarTintManager(this);
     tintManager.setStatusBarTintColor(getResources().getColor(R.color.colorPrimary));
     tintManager.setStatusBarTintEnabled(true);
    

    四.总结

    由于Android系统的开放性,以及系统厂商的不统一,导致Android系统的适配成为了另程序员头疼的一大问题,沉浸式的效果同样不好做到完全统一样式,只能尽力而为之。通过上面的操作,基本可以保证大多数机型和系统的沉浸式效果,但仍然有个别无法适配的系统或机型,这里也无法一一列举所有的情形,需要程序员们有针对性的设计代码,解决问题。

    这里给出自己总结的一个方法,可以在BaseActivity中调用:
    首先,Toolbar要设置fitsSystemWindows属性,如果页面包含EditText,需同时在页面根布局添加fitsSystemWindows属性;
    其次,引用SystemBarTintManager库提供支持;
    最后,调用如下代码:

    private SystemBarTintManager tintManager;
    protected void initWindow() {
        // 4.4及以上版本设置状态栏透明
        Window window = getWindow();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // Translucent status bar
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
    
        // 解决4.4-5.0版本之间,页面包含EditText无法适配的问题
        {
            // create our manager instance after the content view is set
            mTintManager = new SystemBarTintManager(this);
            // enable status bar tint
            mTintManager.setStatusBarTintEnabled(true);
            // enable navigation bar tint
            mTintManager.setNavigationBarTintEnabled(true);
    
            // 自定义状态栏的颜色
            mTintManager.setStatusBarTintColor(getResources().getColor(R.color.colorPrimary));
        }
    
        // 解决[5.0-5.1.1]版本状态栏没有全透明的系统适配问题
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // 解决部分5.x系统使用状态栏透明属性后状态栏变黑色,不使用这句代码,在6.0设备上又出现半透明状态栏
            // 需要特殊处理
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
        }
        
        // 把状态栏标记为浅色,然后状态栏的字体颜色自动转换为深色。
        // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        //     getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
        // }
    }
    

    相关文章

      网友评论

        本文标题:Android 沉浸式详解以及各个版本差异问题

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