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

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

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

一、沉浸式介绍

沉浸式状态栏
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>

效果:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值