A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 翁志雄Gson 中级黑马   /  2016-5-6 10:51  /  13363 人查看  /  64 人回复  /   3 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 翁志雄Gson 于 2016-5-6 11:09 编辑


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


由于Android 系统自4.2 开始 UI 上就没多大改变,而4.4增加了透明状态栏与导航栏的功能如以下图的效果。
从以上的图可以看出ActivitycontentView( setContentView设置的视图)可以延伸到statusBar下方 这种体验就叫沉浸式体验。这个是从用户的角度来感受的。如果从设计师的角度来看就是「Immersive Mode 全浸模式」/「Translucent Bars 半透明状态栏」。不同共同的特点就是“将布局内容延伸到手机状态栏”。

对于这种显示效果又有以下两种模式:
a.全屏( ContentView 可以进入状态栏)
b.非全屏 ( ContentView 与状态栏分离, 状态栏直接着色

2. 案例分析

2.1. sdk5.x以上  

准备5.0模拟器
2.1.1. 非全屏幕: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>

运行效果
2.1.2. 非全屏幕:Javacode着色状态栏
代码位置:com.example.systembar.CodeActivity
① 先写版本判断
② 直接调用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);
    }
}

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

l android:fitsSystemWindows/setFitsSystemWindows

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

2.1.3. 全屏幕: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);
    }
}

运行效果



2.2. 4.4以上
准备4.4模拟器

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


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

代码位置:com.example.systembar.CodeFullActivity#onCreate
① 获取系统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;
}

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

③ 设置 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下可以查看到


l activity.findViewById(Window.ID_ANDROID_CONTENT);获取的是存放layout的FrameLayout具体类型为ContentFrameLayout
l Layout的内容可以从 contentView.getChildAt(0);获取。
l 在状态栏透明的情况下 lp.topMargin -= statusBarHeight;可以使用layout上移

运行效果

2.2.2. 非全屏幕: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背景为绿色
此时还可以去掉系统自带的标题栏
【源代码】

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


2016-05-03_233550.png (53.29 KB, 下载次数: 227)

2016-05-03_233550.png

2016-05-04_000017.png (69.68 KB, 下载次数: 209)

2016-05-04_000017.png

64 个回复

倒序浏览

回帖奖励 +1

老师什么时候带我们一大帮子去大保健啊{:3_57:}{:3_57:}{:3_57:}
回复 使用道具 举报
Studio 发表于 2016-5-6 11:29
老师什么时候带我们一大帮子去大保健啊

你注册黑马的第一句话把我雷倒了。
回复 使用道具 举报
不明觉厉啊。看上去好屌的样子。
虽然看完了,但是我觉得我还是适合第三方,哈哈
回复 使用道具 举报
高大上的界面
回复 使用道具 举报
Mark支持教主
回复 使用道具 举报
666666666666666666
回复 使用道具 举报
这是黑马就业做的事情吗,感觉好牛逼
回复 使用道具 举报
回复 使用道具 举报
6666666666666666666
回复 使用道具 举报
很厉害的样子啊!!!!我们以后干安卓开发就是这样吗?
回复 使用道具 举报
这个太厉害,我看不懂哎,该肿么办?、、、?
回复 使用道具 举报
这已经超出我范围了,看不懂,希望有一天自己也可以写成这样。。。。。
回复 使用道具 举报
真干货!!!!顶
回复 使用道具 举报
值得收藏   赞赞  顶一个
回复 使用道具 举报
支持支持支持支持支持~~~
回复 使用道具 举报
赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞赞
回复 使用道具 举报
虽然看不懂
回复 使用道具 举报
看了一遍之后,就想说一句,这是什么!!!看不懂,基础班和就业班差这么吗?!!
回复 使用道具 举报
已看完,膜拜中
回复 使用道具 举报
1234下一页
您需要登录后才可以回帖 登录 | 加入黑马