与Status Bar和Navigation Bar相关的一些东西

作者:AngelDevil

出处:http://www.angeldevil.me

原文链接:http://www.angeldevil.me/2014/09/02/About-Status-Bar-and-Navigation-Bar/

与StatusBar和NavigationBar相关的东西有两种,一是控制它们的显示与隐藏,二是控制它们的透明与否及背景。

在2.3及以前,StatusBar只能显示与隐藏,即全屏模式,通过WindowManager.LayoutParams.FLAG_FULLSCREEN来实现:

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

并可通过以下Flag使Activity的布局可以使用整个屏幕,状态栏会显示到Activity上方并遮盖部分布局

getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

在3.0(API 11)中,添加了一个重要的方法:setSystemUiVisibility(int),用于控制包括Status Bar在内的一些窗口装饰元素的显示,并添加了View.STATUS_BAR_VISIBLE和View.STATUS_BAR_HIDDEN两个Flag用于控制Status Bar的显示与隐藏,但在4.0(API 14)中废弃了。

在4.0(API 14)中,Andorid引入了Navigation Bar,并添加了一个Flag:SYSTEM_UI_FLAG_HIDDEN_NAVIGATION用于控制Navigatoin Bar的显示。3.0中被弃用的View.STATUS_BAR_VISIBLE被View.SYSTEM_UI_VISIBLE替代,View.STATUS_BAR_HIDDEN被View.SYSTEM_UI_LOW_PROFILE替代,View.SYSTEM_UI_LOW_PROFILE不会使Status Bar和Navigation Bar消失,而是会使它们变暗,降低它们对视觉的干扰,使用户可以专注于应用的内容,但仍可响应用户的交互,当和它们的交互发生时,会退出Low Profile的状态。

在4.1(API 16)中,对Status Bar和Navigation Bar的控制进一步增强,引入了View.SYSTEM_UI_FLAG_FULLSCREEN,和View.SYSTEM_UI_HIDDEN_NAVIGATION分别控制Status Bar和Navigation Bar的显示。并同时引入了另外三个Flag:View.SYSTEM_UI_FLAG_LAYOUT_STABLE、View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION。

显示System UI:

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

隐藏System UI

getWindow().getDecorView().setSystemUiVisibility(          View.SYSTEM_UI_FLAG_FULLSCREEN        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION        | View.SYSTEM_UI_FLAG_IMMERSIVE        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);

通过上面那段View.SYSTEM_UI_FLAG_FULLSCREEN、View.SYSTEM_UI_FLAG_HIDE_NAVIGATION相关的代码实现的全屏模式,可以隐藏掉Status Bar和Navigation Bar,但是这些都是很重要的功能,尤其是Navigation Bar,对于只有虚拟按键的手机,如果隐藏掉Navigation Bar,连切换程序都做不到,所以,当用户和手机有任何交互的时候都会重新显示Status Bar和Navigation Bar,这被称为LEAN BACK模式。这很适合视频播放的场景,但对于其他一些场景可能就不适合了,比如读书。

所以,在4.4(API 19)中引入了沉浸模式View.SYSTEM_UI_FLAG_IMMERSIVE和View.SYSTEM_UI_FLAG_IMMERSIVE_STICK。在IMMERSIVE模式中,用户的普通交互并不会使系统退出IMMERSIVE模式,如果要退出IMMERSIVE模式,需要在屏幕的顶部或底部向内滑动。这可以使用户专注于内容,但退出方式并不像LEAN BACK模式那么明显,所以在第一次进入IMMERSIVE时,系统会弹出一个UI提醒退出的方法。SYSTEM_UI_FLAG_IMMERSIVE等需要和SYSTEM_UI_FLAG_FULLSCREEN、SYSTEM_UI_FLAG_HIDE_NAVIGATION一起使用。

IMMERSIVE_STICKY和IMMERSIVE的区别是,在IMMERSIVE中,用户从屏幕顶部或底部向内滑动时会退出IMMERSIVE模式,需要手动控制再次进入IMMERSIVE模式,而在IMMERSIVE_STICKY模式中,同样的操作只会使系统以半透明方法显示System UI方便用户操作,并会在一段时间后自动隐藏,此时并不会引起onSystemUiVibilityChanged的调用。

可以看到,关于全屏,关于System UI的控制,如果想有好的体验,还是有很多细节需要处理的,不过幸好,chrisbanes大神写了一个类来处理这些细节:https://gist.github.com/chrisbanes/73de18faffca571f7292

除了控制System UI的显示和隐藏外,还可以使它们变成透明的,在4.4(API 19)中还引入了WindowManager.LayoutParams.FLAG_TRANSUCENT_STATUS和WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION用于控制System UI变透明,这两个Flag分别对应于windowTranslucentStatus和windowTranslucentNavigation两个attr,并同时提供了相应的Theme(这些Theme都没有ActionBar),当使用这两个Flag时,SYSTEM_UI_FLAG_LAYOUT_STABLE、SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION会被自动添加。

当System UI变透明后,Activity的UI占据整个屏幕,System

UI覆盖在Activity的UI上面,对于一般的应用,虽然System

UI透明了,但会发现效果并没有那么好,因为ActionBar还是在Status Bar下面,Status

Bar变为透明后会透出Activity的UI,一般情况下这部分UI和ActionBar放到一起并不是那么协调。可以设置窗口的背景和

ActionBar的色调一致,但会引起OverDraw,并且如果指定的布局撑不满全屏呢?

我们知道,Activity顶部的布局是DecorView,而DecorView继承自FrameLayout,所以可以添加两个View到DecorView中,占据Status Bar和Navigation Bar的位置,并设置它们的背景使其与ActionBar相配,但这需要计算Status Bar和Navigation Bar的大小,并且需要判断Navigation Bar的位置(Bottom or Right)。正好,也有人做了这样的事:https://github.com/jgilfelt/SystemBarTint

无论是LEAN_BACK模式还是IMMERSIVE模式,都使用到了4.1中引入的三个Flag:SYSTEM_UI_FLAG_LAYOUT_STABLE、SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,它们的用处并不像SYSTEM_UI_FLAG_FULLSCREEN那么明显,而且名称还很相似,要了解它们的用处,需要先了解一个内容边衬区的概念(ContentInset)及一个重要的函数View.fitSystemWindows。

默认情况下,应用程序窗口在Status Bar下面,系统已经处理好了应用窗口的显示,我们不需要关心Inset和fitSystemWindow,但有一些情况就要我们自己处理了。

当使用了Translucent System UI或SYSTEM_UI_FLAG_FULLSCREEN等时,Activity的UI可以显示到System UI下面,System UI在显示时可能会盖住Activity的UI,所以可能需要处理这样的情况,这就需要知道System UI会占用的空间大小是多少,这个大小就是内容边初区(ContentInset),系统会通过fitSystemWindows(Rect)来通知我们,我们可以通过这个方法调整我们的内容显示。

还有一个方法是View.setFitSystemWindows(boolean),用于设置是否使用系统默认的fitSystemWindows实现。系统的默认实现会消耗掉内容边衬区空间的占用,算到View的Padding里面,并返回true,否则什么也不做返回false,当返回false时,会继续调用View Hierarchy中其他View的fitSystemWindows,直到某一个View中返回true,调用顺序是深度优先。如果我们决定自己处理System UI的空间占用,可以重写VIew的fitSystemWIndows并返回true,如果自己只是做些处理,仍想调用系统的默认实现,要记得调用super.fitSystemWindows并返回false。

接下来就可以说SYSTEM_UI_FLAG_LAYOUT_STABLE等的作用了。在使用View.SYSTEM_UI_FLAG_FULLSCREEN|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION时,Status Bar和Navigation Bar都会隐藏,Activity的UI占据整个屏幕,当System UI再次显示时,应用程序窗口会被Resize,为System UI腾出空间,这会引起屏幕的跳动,这三个Flag的作用就在于此,SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION要和SYSTEM_UI_FLAG_LAYOUT_STABLE一起使用,用于控制当Status Bar或Navigation Bar显示或隐藏时,Activity的UI是否会被Resize,当使用这三个Flag时,Activity会占用整个屏幕空间,并通过fitSystemWindows传入的Insets标明Insets的大小(对于SYSTEM_UI_FLAG_FULLSCREEN会同时包含ActionBar的大小),我们可以根据这个Insets的大小调整内容的显示,如果给ContentView设置fitSystemWindows为true,会自动把Iinset转化为padding。

有几点需要注意的是:

当调用fitSystemWindows时是深度优先遍历

setSystemUiVibility是View中定义的方法,所以我们可以用Activity布局中任意一个View控制System UI,只要这个View不是Gone状态,系统会组合所有可见View的设置,所以一般情况下会直接对DecorView进行设置。

当切换程序时,系统会清除SYSTEM_UI_FLAG_FULLSCREEN等Flag,所以需要通过setSystemUiVisibilityListener、onWindowFocudChanged等方法控制应用的状态。

魅族MX2,Flyme 3.5系统,Android

4.4.4,Immersive模式无法退出,不过这个机型有实体按键,所以影响不大,无法从顶部下拉或底部滑动退出全屏,因为Flyme系统本身就支持

在全屏时拉出状态栏或调出任务切换,系统设置中也可以关闭这个功能。

参考:https://www.youtube.com/watch?v=cBi8fjv90E4&feature=youtu.be

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

推荐阅读更多精彩内容