Anroid沉浸式状态栏

概要

Metarial Design是2014年Google IO的一个重点,在过去的两年时光里,越来越多的公司已经开始认可MD设计规范。在dribbble上可以越来越多的设计师开始投入到MD设计实践中,MD设计规范终于有底气可以和IOS的设计规范对抗啦Android程序员可以很叫嚣滴告诉设计师这就是Android的设计规范。

很少写Material Design的东西,今天趁着手热,在Material化财经APP的时候,看了些透明状态栏/沉浸式状态栏的东西,觉得自己可能还有很多不足之处只是希望能分享出来,一方面是自己的学习成果,另一方面是希望大家指正自己在理解的不到位或者错误。

先放一张我的五儿子手机原生的短信截图:

图1

从上到下,一次是状态栏,内容View,导航栏(有些机器上不一定有导航栏这个虚拟栏),可以看到状态栏是彩色的,不是以前那种黑乎乎的状态栏,现在你也可以定制自己的状态栏了。

现在我们就来看下我手机上装的APP的一些截图:
<span id="pic2">

图2

</span>
这个五个应用分别是网易新闻、豌豆荚、微信、小米天气、小气天气。

关于这个状态栏变色到底叫「Immersive Mode」/「Translucent Bars」有兴趣可以去 为什么在国内会有很多用户把 「透明栏」(Translucent Bars)称作 「沉浸式顶栏」?以及何为沉浸模式,沉浸式顶栏,变色龙状态栏,这个历史原因我们就没法去说大家错误,所有就错说错有了沉浸式状态栏一说。

在5.0之后我们是可以通过v7包下的Theme.AppCompat一些列主题为APP的页面设置Activity的的状态栏,但是为了兼容低版本的我们放弃这种方式。为了能定制自己的状态栏,我们可以手动设置状态栏的颜色,可以随时改变状态栏的透明度等,所以我们需要自己来定制一套可行的方案。

实现

准备

分类

  1. 全屏模式和着色模式
    根据内容延伸的角度可以分为两类:全屏模式和着色模式。其中,图2 中前三个页面都是状态栏固定在上方,无论下面怎么滑动,内部View都是那一块固定的大小区域滑动,由于状态栏是固定在一定位置且有着色,我们称之为着色模式,而图2中后两个页面截图中,内容View和状态栏像放在一个FrameLayout一样,是层叠关系并且状态栏是透明,内容View可以延伸到状态栏,我们称之为全屏模式。

  2. 透明状态栏和彩色状态栏
    根据状态栏的颜色,可以分为状态栏透明和不透明(网易新闻、小米天气都是透明,而豌豆荚、wechat都是不透明)。
    以上两种分为是不同维度的,从不同维度来看可以组合如下图:

setFitsSystemWindows

在android doc是这么描述的:

void setFitsSystemWindows (boolean fitSystemWindows)
Sets whether or not this view should account for system screen decorations such as the status bar and inset its content; that is, controlling whether the default implementation of fitSystemWindows(Rect) will be executed. See that method for more details.

Note that if you are providing your own implementation of fitSystemWindows(Rect), then there is no need to set this flag to true -- your implementation will be overriding the default implementation that checks this flag.

大概意思是:setFitsSystemWindows用来设置影响系统的工具栏如状态栏,决定了这个view是否插入到它的ContentView。当您设置了fitSystemWindows(Rect)而没有将setFitsSystemWindows设置为true,你对fitSystemWindows(Rect)设置是无效的.

该属性可以设置是否为系统 View 预留出空间, 当设置为 true 时,会预留出状态栏的空间。

由于这个实在API14(4.0)之后的函数,为了兼容低版本,才有V4里面的

 ViewCompat.setFitsSystemWindows(rootView,false);

透明状态栏

由于Android 4.4才加入透明状态栏,Android 5.0之后可以直接设置状态栏和导航栏,而不是之前的黑乎乎的状态栏,但是,在4.4以下的系统上,想自己定义状态栏就无能为力了。所以,我们将Android 4.4和Android5.0视为边界。

Android 4.4设置透明状态栏

设置方法有两种:

代码

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // 设置状态栏透明
             activity.getWindow()
                .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            
}

XML

在values-v19文件夹下,为activity的Style 添加一个属性:

<resources>

   <style name="AppTheme" parent="@style/BaseAppTheme">
       <item name="android:windowTranslucentStatus">true</item>
   </style>
</resources>

5.0+透明状态栏

不过对于5.0系统,上面的设置后的结果可能不是透明哦(在原生机器是不透明的,但是在小米的是透明的,估计MIUI做了一些优化工作)

若是要完全透明,就需要看额外处理,在内容延伸到状态栏一节有介绍。

当然了你也可以用5.0的setStatusBarColor

<span id="5status">全屏模式的透明状态栏</span>

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);
    
}

ViewCompat.setFitsSystemWindows(mChildView, false)中的第二个参数设置为false就是全屏模式,而设置成true。像上述实例中, ViewCompat.setFitsSystemWindows(mChildView, false)就是说mChildView可以直接延伸到phoneWindow的顶部,相当于小米天气的那种效果。

彩色状态栏

有透明状态栏,就有彩色状态栏。
在5.0+设置状态栏很简单就参照全屏模式的透明状态栏中的代码做修改window.setStatusBarColor(int color),而对于Android 4.4--5.0的怎么办呢,Android4.4是提供setStatusBarColor这个方法的。

我们就想到了在上面提到的全屏透明状态栏的基础上加一个和状态栏一样高度的空白View放到顶部。

好了说干就干:

        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
 //添加一个空白的view到手机屏幕的顶部
addStatusBarBehind(activity, color, statusBarAlpha);
public static void addStatusBarBehind(Activity activity, int color, int statusBarAlpha) {
        ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
        int       count     = decorView.getChildCount();
        if (count > 0 && decorView.getChildAt(count - 1) instanceof StatusBarView) {
            decorView.getChildAt(count - 1).setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
        } else {
            StatusBarView statusView = createStatusBarView(activity, color, statusBarAlpha);
            decorView.addView(statusView);
        }
        setRootView(activity);
    }

全屏模式

全屏模式,内容延伸到状态栏类似与小米天气的APP,先考虑下怎么做?

答案:将内容移到状态栏下,并且状态栏背景透明.

4.4--5.0

  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // 设置状态栏透明
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //  设置根布局的参数
            ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
            ViewCompat.setFitsSystemWindows(rootView,false);
            rootView.setClipToPadding(true);
        }

其实就先将状态栏设置了透明activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS),而后可以直接设置内容的根View来直接设置ViewCompat.setFitsSystemWindows(rootView,false),这样就可以直接讲根rootView直接顶上去,和状态栏的顶部对齐。

5.0+

在Android 4.4上设置透明状态栏,在5.0上依然可以正常显示,利用5.0实现的全屏模式的透明状态栏不过状态栏实际上并不完全为透明色,会有些许灰色。一般情况下,这个使我们能接受的,如微信、QQ等都是状态栏颜色暗与下面的Toolbar的。

若是能通过Activity的Theme的colorPrimaryDark设状态栏颜色颜色设置,也是可行的,但是若你must实现透明额状态栏,也只能出狠招了。

Window window = activity.getWindow(); 

window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS|
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); 
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);    

setSystemUiVisibility这个可以参考Using Immersive Full-Screen Mode


这样的组合,让我们可以按照自己的需求来定制自己的状态栏,随后会开源自己封装的开源库工供大家参考。

参考文章

  1. Using Immersive Full-Screen Mode
  1. Android实现沉浸式状态栏

  2. Android-transulcent-status-bar

  3. Android状态栏合集-管你透不透明

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容