沉浸式状态栏

何谓沉浸式状态栏##

说白了,沉浸式状态栏本质上就是给系统状态栏着色。当这个颜色和我们Activity中的ToolBar或者ActionBar所使用的背景颜色一致时就会有沉浸式的效果。

怎么给状态栏着色##

那么我们要怎么样才能给系统状态栏着色呢?谷歌后知后觉,终于在API 21Window类中添加了相应的方法,方法声明如下:

public abstract class Window {
  /**
  For this to take effect,the window must be drawing the system bar backgrounds with 
  android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS and 
  android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS must not be set
  **/
  public abstract void setStatusColor(int color);
}

具体的实现在PhoneWindow类中,这里不再深入。既然方法都有了,那么直接调用就行了。这里我们在Activity中将状态栏颜色设置为红色

  Window window = getWindow();
  window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
  window.setStatusBarColor(Color.parseColor("#FF0000"));

注意,上面的代码假设当前系统API Level >= 21,因为只有满足条件的SDK版本才能找到该方法;与此同时,在设置状态栏颜色的同时,API文档 告诉我们还需要同步设置WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS这个Window Flag,并且需要保证WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS这个Window Flag没有被设置。否则,不会生效

在调用任何一个不熟悉的方法时,请首先仔细阅读一下API 文档

上面,我们通过方法调用给系统状态栏着色;当然也可以通过指定Theme来完成;

    <style name="MaterialAppTheme" parent="android:Theme.Material.Light">
        <item name="android:colorPrimaryDark">#FF0000</item>
        <item name="android:statusBarColor">#00FF00</item>
    </style>

Material Theme中继承,覆写android:statusBarColor属性,指定具体颜色值即可。Material Themeandroid:statusBarColor属性的值默认使用android:colorPrimaryDark属性指定的值;所以我们也可以仅仅指定android:colorPrimaryDark属性;
  如果因为某种原因,不从Material Theme中继承,那么就只能老老实实地指定特定的属性不能偷懒,这些属性包括android:statusBarColorandroid:windowDrawsSystemBarBackgrounds

    <style name="CustomAppTheme" parent="android:Theme.Light">
        <item name="android:statusBarColor">#00FF00</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    </style>

这里,我们只从Theme.Light中继承,那就不要指望它能像Material Theme那样帮我们做一些事;android:statusBarColor必须指定,因为它不再有默认的指向android:colorPrimaryDark;此外,android:windowDrawsSystemBarBackgroundstrue必不可少;就像上面使用setStatusColor方法时需要注意的那样,这个属性相当于添加了FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS(当然你也可以不在Theme中指定这个属性,使用如上代码那种方式添加Window Flag);而从Material Theme中继承时没有那样做,是因为Material Theme中它默认值为true

注意,上面Theme的声明,对应的资源文件应该在values-v21文件夹下。因为不管是相应的属性,还是对应的Material Theme都是至少API 21才能使用的

兼容低版本

OK,到此为止,我们所讨论的都是基于API 21以上的。如果低版本该怎么办?低版本的系统是不支持给状态栏着色的,但却可以通过 透明状态栏+透明背景颜色 来实现相同的效果;废话不多说,来看实现。

将系统状态栏设置为透明

这是第一步。可以通过代码方式

  getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

或者Theme Attribute的方式

  <item name="android:windowTranslucentStatus">true</item>
设置对应背景颜色

接下来,就是背景颜色的设置。首先需要将ActionBar或者ToolBar的背景颜色设置为我们需要的颜色,具体如何设置不再深入,请自行研究(这里,如果没有使用到ActionBar或者ToolBar,这一步可直接略过)。

其次,设置Activity根布局的背景颜色为一致的颜色;Just a piece of cake!

最后,我们还需要做一个调整。当设置了状态栏为透明后,Activity会相当于一个FullScreen的全屏设置,窗口会占满整个屏幕,整体的内容会往上移动一段状态栏高度的距离,这样就会导致状态栏覆盖到我们的内容。这时,我们需要在根布局上设置android:fitsSystemWindows="true",这样系统会帮我们重新调整窗口的位置避免出现覆盖的情况(无非就是给我们的窗口加上一个padding值);

注意,上面透明栏+背景色的方式只适用于API 19以上,因为这个版本以上的系统才支持透明化状态栏,所以,19以下的系统不支持沉浸式状态栏

其实系统的导航栏在API 19以上同状态栏一样也支持透明化和设置背景颜色,但这不是本文内容

关于透明化状态栏

上面说到android:windowTranslucentStatus可用于API 19以上的版本透明化状态栏;但请注意,在19版本和19版本以上该属性生效时存在差异。具体表现如下(这里盗用stackoverflow上的一张图说明)

n0aYT.png

上图中,左边为19版本的显示效果,右边为21版本的效果;我们可以从图中看到比较明显的差异。在19版本中,系统给SystemBar添加了一个渐变,而21版本的则是一个透明的纯色。如果我们使用android:windowTranslucentStatus在21版本及以上来实现沉浸式的应用,则最终效果将不会太理想;那么是不是就不能实现了呢?No!

21版本以上的透明系统栏需要使用android:statusBarColor = "@android:color/transparent"来实现;这里android:windowTranslucentStatus肯定是为false的,因为这两个属性是不能同时生效的。但是由于android:windowTranslucentStatus属性的禁用,状态栏将不再会是浮在我们的window上。没关系,我们可以通过下面的方法达到一样的效果:

getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

其实设置android:windowTranslucentStatus属性时,正是系统帮我们设置了上面的Flag;上面我们在DecorView上调用这个方法,但其实可以在任何一个可见的View上进行调用,效果是一样的。下面再补充说明一下setSystemUiVisibility其他可用的标志:

View.SYSTEM_UI_FLAG_VISIBLE Level 14 默认标记

View.SYSTEM_UI_FLAG_LOW_PROFILE Level 14
低功耗模式, 会隐藏状态栏图标, 在4.0上可以实现全屏。status bar和navigation bar的相关图标会被弱化,比如navigation bar的几个虚拟键会弱化成很细微的小点。一旦你再次点击 status bar和navigation bar 的所在区域,他们就会再次完全显现。这种方式的好处是status bar和navigation bar并没有消失,仍然在界面上,但是它们的细节变暗了、模糊了。

View.SYSTEM_UI_FLAG_LAYOUT_STABLE Level 16
保持整个View稳定, 常跟bar 悬浮, 隐藏共用, 使View不会因为SystemUI的变化而做layout

View.SYSTEM_UI_FLAG_FULLSCREEN Level 16
状态栏隐藏(导航栏仍然显示)。跟WindowManager.LayoutParams.FLAG_FULLSCREEN有相同的效果(其实不同,因为该标志下statusbar的高度还是会存在,不算真正意义上的全屏),同时在使用ActionBar的FEATURE_ACTION_BAR_OVERLAY时,启用SYSTEM_UI_FLAG_FULLSCREEN 会将ActionBar隐藏;该标志一般适用于短期的全屏状态而不是长期。

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN Level 16
状态栏上浮于Activity

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION Level 14
暂时隐藏导航栏, 由于导航栏的重要性,当产生细微的用户交互后,比如单击屏幕,都可能会导致navigation bar重新出现,源于系统clear掉该标志与SYSTEM_UI_FLAG_FULLSCREEN 标志,同SYSTEM_UI_FLAG_IMMERSIVE 标志一起使用可避免被clear

View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION Level 16
导航栏上浮于Activity

View.SYSTEM_UI_FLAG_IMMERSIVE Level 19
Kitkat新加入的Flag, 沉浸模式, 跟SYSTEM_UI_FLAG_HIDE_NAVIGATION一起使用才有意义,可以避免系统在产生细微用户交互时系统clear掉SYSTEM_UI_FLAG_HIDE_NAVIGATION标志。如单独使用SYSTEM_UI_FLAG_HIDE_NAVIGATION标志时只需单击屏幕,导航栏就会重新出现;如果同时使用该标志,则不会出现,但用户在导航栏区域仍然可以主动呼出。呼出后,对应的标志会被清除。

View.SYSTEM_UI_FLAG_IMMERSIVE_STIKY Level 19
需要跟SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 或者 SYSTEM_UI_FLAG_FULLSCREEN 一起使用。当单独使用上面的标志时,任何用户交互会导致导航栏重新出现,从顶部向下滑动会重新呼出状态栏,这些操作会导致这些标志被clear掉。如果同时指定SYSTEM_UI_FLAG_IMMERSIVE_STIKY 标志,那么对应标志将不会被清除,且呼出隐藏的bar后会自动再隐藏掉

总结

只有Aos 4.4 API 19 KitKat以上版本才支持沉浸式状态栏!

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

推荐阅读更多精彩内容