(三十五)沉浸式设计以及兼容

来源:互联网 发布:淘宝高仿男鞋店铺 编辑:程序博客网 时间:2024/05/22 07:43

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

一、沉浸式介绍

沉浸式状态栏
Google 从 Android kitkat(android 4.4) 开始,给我们开发者提供了一套能透明的系统 UI 样式给状态栏和导航栏,这样的话就可以调整状态栏和导航栏跟 Activity 一样的样式,形成一个完整的主题。

优点:
1.这样设计的好处就是用户可以沉浸到设计的 App 中,没有其他因素可以影响到用户。
2.更符合整体设计风格,用户所看到的一屏 包含 App 内容 状态栏 内容区,导航栏。
3.内容区为开发者所控制,导航栏与状态栏 为本身系统拥有,沉浸式设计就是为导航栏和状态栏展开。

沉浸式设计的目的就是让 App 的效果其能够与手机整体的状态融为一体。不会因为看到其他不和谐的因素而影响用户。

现在实现沉浸式设计主要是修改状态栏和导航栏的背景颜色。

 平台版本                   API     级别     Android7.0                 24       N                  平台亮点 Android6.0                 23       M                  平台亮点 Android 5.1                22  LOLLIPOP_MR1            平台亮点 Android 5.0                21  LOLLIPOP Android 4.4W               20  KITKAT_WATCH            仅限 KitKat for Wearables Android 4.4                19  KITKAT                  平台亮点 Android 4.3                18  JELLY_BEAN_MR2          平台亮点 Android 4.2、4.2.2          17  JELLY_BEAN_MR1          平台亮点 Android 4.1、4.1.1          16  JELLY_BEAN              平台亮点 Android 4.0.3、4.0.4        15  ICE_CREAM_SANDWICH_MR1  平台亮点 Android 4.0、4.0.1、4.0.2   14   ICE_CREAM_SANDWICH

可以发现,安卓 5.0 以上、安卓 4.4 到 安卓 5.0、安卓 4.4 以下是各不相同的。

1.安卓 5.0 以上

安卓 5.0 以上的版本,要进行状态栏的修改有两种方式。

一种是在 style.xml 中设置主题,通过设置 colorPrimaryDark 可以设置状态栏颜色。
style.xml

<resources>    <!-- Base application theme. -->    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">        <!-- Customize your theme here. -->        <item name="colorPrimary">@color/colorPrimary</item>        <!-- 设置状态栏颜色 -->        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>        <item name="colorAccent">@color/colorAccent</item>    </style></resources>

另一种是安卓在 5.0 以上提供了 setStatusBarColor、setNavigationBarColor 方法分别进行状态栏与导航栏颜色设置,方法使用这个要注意添加版本判断。

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){            //设置状态栏颜色            getWindow().setStatusBarColor(Color.GREEN);            //设置导航栏颜色            getWindow().setNavigationBarColor(Color.GREEN);        }

注:上面方式虽然很方便,但是只能在 5.0 以上使用。

未设置:
这里写图片描述

设置后:
这里写图片描述

2.安卓 4.4 以下

除个别手机厂商对 API 进行修改外,4.4以下是不支持的,所以还是放弃吧。

3.安卓 4.4 到 5.0

在安卓 4.4 上,按 5.0 那要进行主题的设置一样是没有效果的。针对这种情况, 4.4 在 style.xml 中也有对应的属性可以设置。

        //  将导航栏编程透明        <item name="android:windowTranslucentNavigation">true</item>        //将状态栏设置成透明        <item name="android:windowTranslucentStatus">true</item>

对应的使用代码进行设置的方法:

        //必须在 setContentView 之前        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);        }

效果:
这里写图片描述

但是,这种方式只能设置是否透明。

二、安卓 4.4 到 5.0 的解决方案

1.使用 ToolBar

MainActivity :

public class MainActivity extends AppCompatActivity {    Toolbar toolbar;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);        }        setContentView(R.layout.activity_main);        toolbar = findViewById(R.id.toolbar);        toolbar.setTitle("首页");        setSupportActionBar(toolbar);    }}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout 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"    tools:context="com.xiaoyue.statusbar.MainActivity">    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:background="@color/colorPrimary"        android:layout_width="match_parent"        android:layout_height="wrap_content">    </android.support.v7.widget.Toolbar></android.support.constraint.ConstraintLayout>

style.xml:

<resources>    <!-- 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></resources>

效果:
这里写图片描述

单纯的使用 ToolBar,会让 ToolBar 的高度包括了状态栏的高度(ToolBar 中整体高度变大)。状态栏设为透明的时候,是不占空间的。

2.fitsSystemWindows

在布局文件添加 fitsSystemWindows 属性。

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fitsSystemWindows="true"    tools:context="com.xiaoyue.statusbar.MainActivity">    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:background="@color/colorPrimary"        android:layout_width="match_parent"        android:layout_height="wrap_content">    </android.support.v7.widget.Toolbar></android.support.constraint.ConstraintLayout>

这个一个 boolean 值的内部属性,让 view 可以根据系统窗口(如 StatusBar)来调整自己的布局,如果值为true,就会调整 view 的 paingding 属性来给 system windows 留出空间。

实际效果:
当 StatusBar 为透明或半透明时(4.4以上),系统会设置 view 的 paddingTop 值为一个适合的值( status bar的高度)让 view 的内容不被上拉到状态栏,当在不占据 StatusBar 的情况下(4.4以下)会设置 paddingTop 值为0(因为没有占据 StatusBar 所以不用留出空间)。

这种处理方式不仅每个布局都要进行这个属性设置,而且在某些情况下会导致布局异常,特别是在使用 ScrollView 的时候。我们可以根据这个思路来换一种解决方式。

3.添加 View

在 ToolBar 上面添加一个状态栏高度的 View。

MainActivity :

public class MainActivity extends BaseActivity {    Toolbar toolbar;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        toolbar = findViewById(R.id.toolbar);        toolbar.setTitle("首页");        setSupportActionBar(toolbar);        View view = findViewById(R.id.nav);        setToolBarStyle(toolbar, view, Color.GREEN);    }}

把对状态栏的处理写在 BaseActivity 中,这样所有的 Activity 直接继承即可。

BaseActivity :

public class BaseActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);        }    }    public void setToolBarStyle(Toolbar toolbar, View topView, int styleColor) {        // 4.4 到 5.0        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT                && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {            if (toolbar != null) {                int statusHeight=getStatusHeight();                Log.i("tuch", "   statusHeight  " + statusHeight);                //第一种方式//                ViewGroup.LayoutParams layoutParams = topView.getLayoutParams();//                layoutParams.height = statusHeight;//                topView.setBackgroundColor(styleColor);                //第二种                toolbar.setPadding(0,toolbar.getPaddingTop()+statusHeight,0,0)            }        //5.0 以上        }else if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP) {        }else {            //没救了        }    }    /**     * 通过反射获取状态栏高度     * @return     */    private int getStatusHeight() {        int height = -1;        try {            Class<?> clazz = Class.forName("com.android.internal.R$dimen");            Object object = clazz.newInstance();            String heightStr = clazz.getField("status_bar_height").get(object).toString();            height = Integer.parseInt(heightStr);            //dp--px            height = getResources().getDimensionPixelSize(height);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (NoSuchFieldException e) {            e.printStackTrace();        }        return height;    }}

这里有两种方式,第一种是在 ToolBar 上方添加一个 View,通过设置 View 来控制状态栏,包括背景颜色(推荐这种方式)。第二种是按 fitsSystemWindows 的原理,添加 Padding。

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.xiaoyue.statusbar.MainActivity">    <View        android:id="@+id/nav"        android:layout_width="match_parent"        android:layout_height="1dp"/>    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:background="@color/colorPrimary"        android:layout_width="match_parent"        android:layout_height="wrap_content">    </android.support.v7.widget.Toolbar>    <TextView        android:layout_width="match_parent"        android:layout_height="match_parent"        android:text="Hello World"/></LinearLayout>

第一种:

这里写图片描述

第二种:

这里写图片描述

4.导航栏的处理

导航栏处理思路跟 状态栏一样,不过有些手机是没有导航栏的,直接是物理按键,所以需要先判断是否有导航栏存在。

BaseActivity :

public class BaseActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);        }    }    public void setToolBarStyle(Toolbar toolbar,View topView, View bottomView, int styleColor) {        // 4.4 到 5.0        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT                && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {            if (toolbar != null) {                int statusHeight=getStatusHeight();                Log.i("tuch", "   statusHeight  " + statusHeight);                //第一种方式                ViewGroup.LayoutParams layoutParams = topView.getLayoutParams();                layoutParams.height = statusHeight;                topView.setBackgroundColor(styleColor);                //第二种//                toolbar.setPadding(0,toolbar.getPaddingTop()+statusHeight,0,0)                //下面的导航栏                if (haveNavgtion()) {                    ViewGroup.LayoutParams layoutParamsBottom = bottomView.getLayoutParams();                    layoutParamsBottom.height = getNavigationHeight();                    Log.i("tuch", "getNavigationHeight  " + getNavigationHeight());                    bottomView.setBackgroundColor(styleColor);                }            }        //5.0 以上        }else if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP) {        }else {            //没救了        }    }    /**     * 通过反射获取状态栏高度     * @return     */    private int getStatusHeight() {        int height = -1;        try {            Class<?> clazz = Class.forName("com.android.internal.R$dimen");            Object object = clazz.newInstance();            String heightStr = clazz.getField("status_bar_height").get(object).toString();            height = Integer.parseInt(heightStr);            //dp--px            height = getResources().getDimensionPixelSize(height);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (NoSuchFieldException e) {            e.printStackTrace();        }        return height;    }    /**     * 判断是否有导航栏(API 17 以后才可以)     * @return     */    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)    private boolean haveNavgtion() {        //屏幕的高度,真实物理的屏幕        Display display = getWindowManager().getDefaultDisplay();        DisplayMetrics displayMetrics = new DisplayMetrics();        display.getRealMetrics(displayMetrics);        int heightDisplay = displayMetrics.heightPixels;        //为了防止横屏        int widthDisplay = displayMetrics.widthPixels;        //显示内容的高度        DisplayMetrics contentDisplaymetrics = new DisplayMetrics();        display.getMetrics(contentDisplaymetrics);        int contentDisplay = contentDisplaymetrics.heightPixels;        int contentDisplayWidth = contentDisplaymetrics.widthPixels;        //屏幕内容高度  显示内容的屏幕        int w = widthDisplay - contentDisplayWidth;        //哪一方大于0   就有导航栏        int h = heightDisplay - contentDisplay;        return w>0||h>0;    }    private int getNavigationHeight() {        int height=-1;        try {            Class<?> clazz=Class.forName("com.android.internal.R$dimen");            Object  object=clazz.newInstance();            String heightStr=clazz.getField("navigation_bar_height").get(object).toString();            height = Integer.parseInt(heightStr);            //dp--px            height = getResources().getDimensionPixelSize(height);        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (NoSuchFieldException e) {            e.printStackTrace();        }        return height;    }}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.xiaoyue.statusbar.MainActivity">    <View        android:id="@+id/nav"        android:layout_width="match_parent"        android:layout_height="1dp"/>    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:background="@color/colorPrimary"        android:layout_width="match_parent"        android:layout_height="wrap_content">    </android.support.v7.widget.Toolbar>    <TextView        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"        android:text="Hello World"/>    <View        android:id="@+id/bottom"        android:layout_gravity="bottom"        android:layout_width="match_parent"        android:layout_height="1dp"/></LinearLayout>

效果:

这里写图片描述