Android中的系统栏(状态栏与导航栏)

简介

Android系统中的系统栏可以分为状态栏与导航栏,具体指的如下:


官方提供的状态栏的示例图

状态栏:StatusBar

官方提供的导航栏示例图

导航栏:NavigationBar

需要注意的是,现在手机为了追求更高的屏幕占比,导航栏物理按键很多都变成了虚拟按键.

正常来讲,应用程序内容区域与系统栏共存,但是显示沉浸式内容的应用程序(如电影或图像)可以暂时调暗系统栏图标,以减少分散注意力的体验,或暂时隐藏条形图以获得完全身临其境的体验。

基础调节系统栏

说明:所谓的调节简单讲就是隐藏显示以及颜色的设置.
系统提供了如下的API来帮助开发者完成奖要求:

View decorView = context.getWindow().getDecorView();
decorView.setSystemUiVisibility( "系统提供的值");
//在你想使用的Activity中调用即可.
其中上述系统提供的值可选项如下:

原图:


原图
1

View.SYSTEM_UI_FLAG_LOW_PROFILE
代码

 View db_View = getWindow().getDecorView();
 db_View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);

解释说明

系统栏进入不引人瞩目的"低调模式"
这适用于游戏,书籍阅读器,视频播放器或任何其他“沉浸式”应用程序,通常的系统被认为太分散注意力。
在低调模式下,状态栏和/或导航图标可能会变暗
另外如何用户手动触摸了状态栏等操作,那么这个标志就会消除了,需要在设置.

效果图:

1.png

对比可以看出,将状态栏进行了弱化,但是依旧存在,当用户触摸一下状态栏,那么就会恢复到原图的样式.如果还想要保持这效果,需要重置可以如下:

 @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
       if(hasFocus){
            //用户下拉状态栏后关闭状态栏回到当前Activity界面上时候
             View decorView = getWindow().getDecorView();
            int status = SYSTEM_UI_FLAG_LOW_PROFILE;
            decorView.setSystemUiVisibility(status);
            }
    }
2

View.SYSTEM_UI_FLAG_FULLSCREEN
代码

View db_View = getWindow().getDecorView();
db_View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);

解释如下:

会进入正常的全屏模式,使内容可以覆盖屏幕.但是仍可以允许用户进行交互,比如触摸屏幕顶部,
但是与前面的类似触摸一次此Flag就会清除.
意味着装饰栏(如状态栏)在当前窗口隐藏.
这个属性与android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN
     * WindowManager.LayoutParams.FLAG_FULLSCREEN 效果一致.
这个修饰符可以覆盖掉ActionBar.

隐藏状态栏与导航栏.
效果如下:


2.png

一旦用户触摸状态栏,该标志也会取消,需要在重新设置,采用1里面的方式设置即可.(这样在代码中设置,优先级高)

3

SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
代码:

 View db_View = getWindow().getDecorView();
 db_View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_FULLSCREEN);

解释如下:

View会按照要求进行布局.
如果没有SYSTEM_UI_FLAG_FULLSCREEN ,依旧允许它在切入和退出该模式时避免伪像(模糊化,像素化,在3.2以上版本,
系统会在320dp x 480dp屏幕上绘制布局,然后将其缩放以填满屏幕,这就会现伪像.),
代价是当它们的一些用户界面在显示时被屏幕装饰(如状态栏)覆盖。
您可以执行内部UI元素的布局,以通过该方法考虑非全屏系统UI.
如果配合SYSTEM_UI_FLAG_FULLSCREEN使用,结果仍是全屏.(建议配合使用)
3.png
4

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
代码:

View db_View = getWindow().getDecorView();
db_View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

解释如下:

正如字面翻译,系统导航栏暂时隐藏.
这是一种比SYSTEM_UI_FLAG_LOW_PROFILE所要求的更为突兀的状态
只支持虚拟按键(Back,Home,the like)设备,会让其消失.
This is useful (in conjunction with the{@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} 
and{@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN}window flags) 
for displaying content using every last pixel on the display.
有一个限制,导航控件很关键,用户最少的互动将使他们重现,并且当前标志与SYSTEM_UI_FLAG_FULLSCREEN将自动清除,
以便状态栏与导航键两个关键因素重新展示.

效果如下:


4.png

将底部的虚拟导航键都给隐藏了.

5

SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
代码如下:

  View db_View = getWindow().getDecorView();
db_View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);

解释如下:

即使它目前还没有设置SYSTEM_UI_FLAG_HIDE_NAVIGATION
它扔就允许它在切换进入和退出该模式时避免伪像
与SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN的作用类似,如何配合SYSTEM_UI_FLAG_HIDE_NAVIGATION,结果仍是全屏.(建议配合使用)

效果如下:


5.png
6

SYSTEM_UI_FLAG_LAYOUT_STABLE

保持整个View稳定, 常和控制System UI悬浮, 隐藏的Flags共用, 使View不会因为System UI的变化而重新layout
7

SYSTEM_UI_FLAG_IMMERSIVE

当使用SYSTEM_UI_FLAG_HIDE_NAVIGATION隐藏导航栏时,View希望保持交互状态。 如果这个标志
 未设置,系统会在任何用户交互时强制清除{@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}。
所以这个标志是其专门的修饰符.
8

SYSTEM_UI_FLAG_IMMERSIVE_STICKY

当你使用SYSTEM_UI_FLAG_FULLSCREEN 隐藏栏  and/or 使用SYSTEM_UI_FLAG_HIDE_NAVIAGTION 隐藏导航栏,
额外加上这个标志,可以创建身临其境的体验.
这个标志符只能和这两者或者某个配合使用,才会有效果.
如果没有设置这个标志,那么上面两个标志,在用户触摸顶部状态栏时候会失效
当系统条隐藏在沉浸式模式中时,它们可以通过系统手势暂时显示出来,比如触摸屏幕顶部.会在短暂的时间内恢复.
9

SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR

SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

请求导航栏以与光导航栏背景兼容的模式绘制。
     * For this to take effect, the window must request
     * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
     *         FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not
     * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION
     *         FLAG_TRANSLUCENT_NAVIGATION}.

代码

 View db_View = getWindow().getDecorView();
db_View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);

效果图:


9.png

类似于修改状态栏与按钮的颜色的效果.一般系统都是两套,一套黑颜色,一套白颜色.这个确定使用深色的,默认是使用白色的.

10

SYSTEM_UI_FLAG_VISIBLE

系统正常默认的系统栏样式

下面记载一些别的办法


记录展示全屏模式的例子

通过设置标志

   //启用常规沉浸式模式。
    //对于“向后倾斜”模式,删除SYSTEM_UI_FLAG_IMMERSIVE。
    //或者“粘性沉浸式”,用SYSTEM_UI_FLAG_IMMERSIVE_STICKY替换它
View decorView = getWindow().getDecorView();
    decorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_IMMERSIVE
            //设置内容显示在系统栏下面,以便
            //当系统栏隐藏和显示时,内容不会调整大小。
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN //完全体现这三者的"辅助"作用.
            //隐藏导航栏和状态栏
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_FULLSCREEN);

别的方法设全屏

设置主题
    android:theme = “@ android:style / Theme.Holo.NoActionBar.Fullscreen” > 
4.0以下
if (Build.VERSION.SDK_INT < 16) {
           getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }

记录设置状态栏的例子

比较好用的属性,适用于21及以上

<item name="android:windowTranslucentStatus">true</item>
设置状态栏半透明,但是并没有设置全透明的主题(如有请留言告诉我)

效果图:


结果如图

这样看可能效果不明显,调整布局,设置红色部分高40dp,结果如下:


7.png
发现内容区域顶到了上面的状态栏了.可以认为是一种半沉浸式样子.

如果不想这样,可以通过设置

android:fitsSystemWindows= true

这一属性。设置为true让Activity 中setContentView的布局不覆盖状态栏(即相当于给状态栏设置了padding),这个属性要在根布局中使用,如果同时设置了,效果如下:


88.png
重要补充:
如果按照上面设置,那么有的手机半透明会有一层灰色的模板,有的手机是完全透明的。如果想完全都是透明,而不是看系统要求。
可以不要上面那些如下设置:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            var dector = window.decorView
            dector.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            window.statusBarColor = ColorUtils.blendARGB(Color.TRANSPARENT,Color.WHITE,0.0f)
        }
可以实现全透明的沉浸式、原理就是设置状态栏颜色为透明的白色,然后让内容进入到状态栏下面

既然StatusBar由此方法,那么NavigationBar也有类似方法:

        <item name="android:windowTranslucentNavigation">true</item>

效果如下:


33.png

发现是灰色的,这是因为内容区域填充到了导航键区域与前面StatusBar类似,如果也添加fitsystemwindow = true


54.png

记录修改状态栏颜色例子

        <item name="android:statusBarColor" tools:ignore="NewApi">#03A9F4</item>
66.png

如果同时和上一部分提到的设置状态栏透明使用效果如何:


676.png

发现设置颜色就不管用了,其实很好理解,状态栏设置透明了,还设置颜色有什么用.

在代码中使用 context.getWindow().setStatusBarColor(Color.xxxx);
正常使用没事,如果使用
         //设置状态栏颜色为全透明
            context.getWindow().setStatusBarColor(Color.TRANSPARENT);
那么状态栏哪里一片白,需要配合
 {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
 {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
这两个Flag才可以有效果,后面Demo1就是演示例子.

示例修改导航栏颜色

既然有修改状态栏颜色代码,那么也就有修改导航栏的代码:
21及以上可以使用

        <item name="android:navigationBarColor" tools:ignore="NewApi" >#03A9F4</item>

效果如下:


879.png
代码中动态使用
    //设置导航键颜色也为全透明
            context.getWindow().setNavigationBarColor(Color.TRANSPARENT);
但是也需要配合
 {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
 {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
两个Flag来使用.

示例提供的别的方法属性

1 改状态栏上字的颜色
在23提供的方法
        <item name="android:windowLightStatusBar" tools:ignore="NewApi">true</item>

让状态栏上的字的使用深色.

2 改变导航栏
在23中提供的办法
        <item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
3 针对于bar与内容区域的细线位置
在27中添加
        <item name="android:navigationBarDividerColor" tools:ignore="NewApi">#FFC107</item>
在系统导航栏和应用程序内容之间显示指定细线的颜色

上面补充提到的效果展示如下:

        <item name="android:statusBarColor" tools:ignore="NewApi">#03A9F4</item>
        <item name="android:navigationBarColor" tools:ignore="NewApi" >#03A9F4</item>
        <item name="android:windowLightStatusBar" tools:ignore="NewApi">true</item>
        <item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
        <item name="android:navigationBarDividerColor" tools:ignore="NewApi">#FFC107</item>

效果图:在8.1上运行的,可以看到细细的黄线


Screenshot_2019-04-08-16-14-48-20.png

响应UI可见性更改(监听)

View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
        (new View.OnSystemUiVisibilityChangeListener() {
    @Override
    public void onSystemUiVisibilityChange(int visibility) {
        // Note that system bars will only be "visible" if none of the
        // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
            // TODO: The system bars are visible. Make any desired
            // adjustments to your UI, such as showing the action bar or
            // other navigational controls.
        } else {
            // TODO: The system bars are NOT visible. Make any desired
            // adjustments to your UI, such as hiding the action bar or
            // other navigational controls.
        }
    }
});

备注:

前面提到的通过主题设置状态栏与导航栏,在<item>标签中有 tools:ignore="NewApi"
其实在项目中,这部分最好是多写几个value-v21或者value-v23,因为系统是5.0开始提供修改
状态栏颜色的,6.0开始修改状态栏上面文字的颜色的.
总体来讲两种方式,一种是通过主题,一种是通过代码,都可以去完成想要的效果.

Demo时间

(1)示例一:

if (Build.VERSION.SDK_INT >= 21) {

         decorView.setSystemUiVisibility(
                             View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                            | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            );
            //设置状态栏颜色为透明
            context.getWindow().setStatusBarColor(Color.TRANSPARENT);
            //设置导航键颜色也为透明
            context.getWindow().setNavigationBarColor(Color.TRANSPARENT);
        } else {
            //5.0以下,就单纯的全屏就完了
            decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
        }

效果如下:

微信截图_20190409112554.png

(2)示例二 通过主题来演示

因为下面的代码是放在value-v23文件夹下,在value或者value-v21文件夹下,需要把不符合版本的哪个属性删除,这里
只是演示:

  <style name="CarCalculatorTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:statusBarColor">@color/color_wirte</item>
        <item name="android:windowLightStatusBar">true</item>
    </style>

效果图如下:

1556342728(1).jpg

(3)实例三 代码动态设置

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
            window.statusBarColor = ColorUtils.blendARGB(Color.TRANSPARENT, Color.WHITE, 0.0f)
        }

上述代码也可以完成沉浸式的效果。

总结感觉已经可以满足日常开发的需要

未完待续,有补充的欢迎留言~

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

推荐阅读更多精彩内容