Android全屏沉浸式应用

来源:互联网 发布:lsv软件 编辑:程序博客网 时间:2024/04/26 05:27

原文出处:http://bbs.itheima.com/thread-298355-1-1.html?zztj3?rss

一、概念

首先让我们看一下默认状态栏的显示效果 以下以微信与qq为例:

这里写图片描述

由于Android 系统自4.2 开始 UI 上就没多大改变,而4.4增加了透明状态栏与导航栏的功能如以下图的效果。

这里写图片描述

从以上的图可以看出Activity的contentView( 即setContentView设置的视图)可以延伸到statusBar下方 这种体验就叫沉浸式体验。这个是从用户的角度来感受的。如果从设计师的角度来看就是Immersive Mode 全浸模式,Translucent Bars 半透明状态栏。不同共同的特点就是“将布局内容延伸到手机状态栏”。

对于这种显示效果又有以下两种模式

1、全屏( ContentView 可以进入状态栏)

这里写图片描述

2、非全屏 ( ContentView 与状态栏分离, 状态栏直接着色

这里写图片描述

二、案例分析

sdk5.x以上 ,准备5.0模拟器

非全屏幕:theme默认主题着色状态栏

根据5.0以上的theme配置要求。只需配置colorPirmary(标题栏颜色),colorPrimaryDark(手机状态栏颜色)即可.

在values/styles.xml创建主题

<resources>    <!--应用的基本主题 -->    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">    <!-- 自定义应用主题 -->        <!--标题颜色-->        <item name="colorPrimary">@color/colorPrimary</item>        <!--状态栏颜色-->        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>        <!--text /checkBox颜色-->        <item name="colorAccent">@color/colorAccent</item>    </style></resources>

在systembar/src/main/AndroidManifest.xml引用

<application    android:allowBackup="true"    android:icon="@mipmap/ic_launcher"    android:label="@string/app_name"    android:supportsRtl="true"    android:theme="@style/AppTheme">    <!-这里是activity -></application>

运行效果

这里写图片描述

非全屏幕:Javacode着色状态栏

代码位置:com.example.systembar.CodeActivity
1、先写版本判断
2、直接调用setStatusBarColor

Activity activity = this;int color=Color.parseColor("#008000");//针对版本5.x以上的即LOLLIPOP以上的if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {    //非全屏幕修改状态栏颜色    Window window = activity.getWindow();    //FLAG_TRANSLUCENT_STATUS为状态栏类型:半透明效果    //取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏    window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);    //需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色    //FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS为状态栏类型:支持着色   window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);    //设置状态栏颜色  setStatusBarColor要求21以上    window.setStatusBarColor(color);    ViewGroup contentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);    View childView = contentView.getChildAt(0);//对应activity布局文件根标签    if (childView != null) {    //注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View . 预留出系统 View 的空间.        ViewCompat.setFitsSystemWindows(childView, true);    }}

运行效果:根据标题颜色着色

这里写图片描述

android:fitsSystemWindowssetFitsSystemWindows()

所有实现 Translucent System Bar 效果的Activity,都需要在根布局里设置 android:fitsSystemWindows=”true” 。设置了该属性的作用在于,不会让系统导航栏和我们app的UI重叠,导致交互问题.以下给出效果图说明该属性。

这里写图片描述

全屏幕:contentview延伸

代码位置:com.example.systembar.CodeFullActivity#onCreate

这里写图片描述

//去掉titlebar-全屏模式supportRequestWindowFeature(Window.FEATURE_NO_TITLE);//细节supportRequestWindowFeature一定要在setContentView之前设置setContentView(R.layout.activity_code_full);Activity activity = this;int statusColor = Color.parseColor("#008000");//针对版本5.x以上的即LOLLIPOP以上的if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {    Window window = activity.getWindow();    //设置透明状态栏,这样才能让 ContentView 向上    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);    //需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色    window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);    //设置状态栏颜色    window.setStatusBarColor(statusColor);    ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);    View mChildView = mContentView.getChildAt(0);    if (mChildView != null) {        //注意不是设置 ContentView 的 FitsSystemWindows, 而是设置 ContentView 的第一个子 View .        // 使其不为系统 View 预留空间.不预留空间的话 状态栏就会覆盖布局顶部        ViewCompat.setFitsSystemWindows(mChildView, false);    }}

运行效果

这里写图片描述

4.4以上,准备4.4模拟器

这里写图片描述

5.x以上的实现方式不使4.4以上的生效.所以要考虑一下兼容方案。

全屏幕:contentview延伸

思路:暂时保存标题栏时可以清楚得看到只要将contentView延伸到statusbar下方.它与statusBar共同放在一个FrameLayout里

这里写图片描述

代码位置:com.example.systembar.CodeFullActivity#onCreate

1、获取系统statusBar的高度

private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height";public static int getStatusBarHeight(Context context) {    int result = 0;    //访问android.jar内的dimen中包含的status_bar_height属性值    int resourceId = context.getResources().getIdentifier(STATUS_BAR_HEIGHT_RES_NAME, "dimen", "android");    if (resourceId > 0) {        result = context.getResources().getDimensionPixelSize(resourceId);    }    return result;}

2、设置无标题栏

//去掉titlebar-全屏模式supportRequestWindowFeature(Window.FEATURE_NO_TITLE);//细节supportRequestWindowFeature一定要在setContentView之前设置setContentView(R.layout.activity_code_full);

3、设置 contentView的marginTop上移状态栏高度

//KITKAT为4.4sdk的名称if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {    Window window = activity.getWindow();    ViewGroup contentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);    //首先使 ChildView 不预留空间    View childView = contentView.getChildAt(0);//layout file对应的根标签    if (childView != null) {        //此时status会遮盖contnetview        ViewCompat.setFitsSystemWindows(childView, false);    }    int statusBarHeight = getStatusBarHeight(activity);    //需要设置这个 flag 才能设置状态栏    window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);    //避免多次调用该方法时,多次移除了 View    if (childView != null && childView.getLayoutParams() != null && childView.getLayoutParams().height == statusBarHeight) {        //移除假的 View.        contentView.removeView(childView);        childView = contentView.getChildAt(0);    }    if (childView != null) {        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) childView.getLayoutParams();        //清除 ChildView 的 marginTop 属性        if (lp != null && lp.topMargin >= statusBarHeight) {            //减少layout的topmargin 使用layout布局的整体延伸到statusBar下方            lp.topMargin -= statusBarHeight;            childView.setLayoutParams(lp);        }    }}

Deug下可以查看到

这里写图片描述

  • activity.findViewById(Window.ID_ANDROID_CONTENT);获取的是存放layout的FrameLayout具体类型为ContentFrameLayout

  • Layout的内容可以从 contentView.getChildAt(0);获取

  • 在状态栏透明的情况下 lp.topMargin -= statusBarHeight;可以使用layout上移

运行效果

这里写图片描述

非全屏幕:Javacod着色状态栏

  • 获取系统状态栏高度(同上)
  • 在状态栏透明情况下下移contnetView 距离为状态栏高度
  • 如果存在着色View则修改背景色
  • 如果不存在着色View则添加同时设置背景色
//判断当前sdk是4.4  KITKAT为4.4sdk的名称    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {        Window window = activity.getWindow();        ViewGroup contentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);        //设置状态栏透明        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);        //获取状态栏高度        int statusBarHeight = getStatusBarHeight(activity);        //在全屏模式下 使用contentView内容下移状态栏高度        View childView = contentView.getChildAt(0);        if (childView != null) {            FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) childView.getLayoutParams();            //如果已经为 ChildView 设置过了 marginTop, 再次调用时直接跳过            if (lp != null && lp.topMargin < statusBarHeight && lp.height != statusBarHeight) {                //不预留系统空间                ViewCompat.setFitsSystemWindows(childView, false);                lp.topMargin += statusBarHeight;//在状态栏透明的情况下 contentView marginTop改为状态栏高度                childView.setLayoutParams(lp);            }        }       //下移的状态栏高度  已经存在着色View直接设置color        View statusBarView = contentView.getChildAt(0);        if (statusBarView != null && statusBarView.getLayoutParams() != null && statusBarView.getLayoutParams().height == statusBarHeight) {            //避免重复调用时多次添加已经着色的View            statusBarView.setBackgroundColor(statusColor);        }else        {            //如果未存在刚添加着色View下次通过contentView.getChildAt(0);即为该着色View            statusBarView = new View(activity);            ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);            statusBarView.setBackgroundColor(statusColor);            //向 ContentView 中添加已经着色的View            contentView.addView(statusBarView, 0, lp);        }    }}

运行效果,我在此处添加的着色View背景为绿色
这里写图片描述

此时还可以去掉系统自带的标题栏

【源代码】http://pan.baidu.com/s/1slOj6sl

开源第三方SystemBarTint

下面介绍一个将以上过程封装比较到位的第三方开源状态栏工具库
支持4.4以上
Github地址:https://github.com/Ztiany/SystemBarTint
运行效果

4.4以上
这里写图片描述

5.x以上
这里写图片描述

在android5.0以上

<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">        <item name="colorPrimary">@color/titleBlue</item>        <item name="colorPrimaryDark">#3A5FCD</item>        <item name="@android:textColorPrimary">@android:color/white</item>    </style>    <style name="AppTheme" parent="AppBaseTheme">        <!-- 隐藏标题栏 -->        <item name="android:windowNoTitle">true</item>        <item name="android:windowDrawsSystemBarBackgrounds">true</item>        <item name="android:statusBarColor">@color/transparent</item>        <!--<item name="colorControlNormal">@color/white</item>-->    </style>

当statusBarColor设置为透明色后,状态栏的颜色为白色,如果布局文件加上属性android:fitsSystemWindows=”true”后,状态栏则显示colorPrimaryDark颜色

styles(4.0之前)

<!-- 半透明的主题样式 -->   <style name="NavigationTransparent" parent="AppTheme">       <!-- Android 4.4 之前的版本跟随系统默认的样式-->   </style>

styles(4.4之后)

<!-- 半透明的主题样式 -->   <style name="NavigationTransparent" parent="AppTheme">       <!-- 状态栏 半透明 -->       <item name="android:windowTranslucentStatus">true</item>       <!-- 导航栏 半透明-->       <item name="android:windowTranslucentNavigation">true</item>   </style>

styles(5.0之后)

<!-- 半透明的主题样式 -->   <style name="NavigationTransparent" parent="AppTheme">       <!-- 导航栏 半透明-->       <item name="android:windowTranslucentNavigation">true</item>       <!-- 状态栏 半透明 -->       <item name="android:windowTranslucentStatus">true</item>       <!-- Android 5.0开始需要把颜色设置为透明。否状态栏会用系统默认的浅灰色 (Android 5.0以后支持修改颜色,需指定颜色)-->       <item name="android:statusBarColor">@android:color/transparent</item>   </style>
0 0
原创粉丝点击