Android动态控制状态栏显示和隐藏
记得之前有朋友在留言里让我写一篇关于沉浸式状态栏的文章,正巧我确实有这个打算,那么本篇就给大家带来一次沉浸式状态栏的微技巧讲解。
其实说到沉浸式状态栏这个名字我也是感到很无奈,真不知道这种叫法是谁先发起的。因为android官方从来没有给出过沉浸式状态栏这样的命名,只有沉浸式模式(immersive mode)这种说法。而有些人在没有完全了解清楚沉浸模式到底是什么东西的情况下,就张冠李戴地认为一些系统提供的状态栏操作就是沉浸式的,并且还起了一个沉浸式状态栏的名字。
比如之前就有一个qq群友问过我,像饿了么这样的沉浸式状态栏效果该如何实现?
这个效果其实就是让背景图片可以利用系统状态栏的空间,从而能够让背景图和状态栏融为一体。
本篇文章当中我会教大家如何实现这样的效果,但这个真的不叫沉浸式状态栏。因此,这算是一篇技术+普及的文章吧,讲技术的同时也纠正一下大家之前错误的叫法。
什么是沉浸式?
先来分析一下叫错的原因吧,之所以很多人会叫错,是因为根本就不了解沉浸式是什么意思,然后就人云亦云跟着叫了。那么沉浸式到底是什么意思呢?
根据百度百科上的定义,沉浸式就是要给用户提供完全沉浸的体验,使用户有一种置身于虚拟世界之中的感觉。
比如说现在大热的vr就是主打的沉浸式体验。
那么对应到android操作系统上面,怎样才算是沉浸式体验呢?这个可能在大多数情况下都是用不到的,不过在玩游戏或者看电影的时候就非常重要了。因为游戏或者影视类的应用都希望能让用户完全沉浸在其中,享受它们提供的娱乐内容,但如果这个时候在屏幕的上方还显示一个系统状态栏的话,可能就会让用户分分钟产生跳戏的感觉。
那么我们来看一下比较好的游戏都是怎么实现的,比如说海岛奇兵:
海岛奇兵的这种模式就是典型的沉浸式模式,它的整个屏幕中显示都是游戏的内容,没有状态栏也没有导航栏,用户玩游戏的时候就可以完全沉浸在游戏当中,而不会被一些系统的界面元素所打扰。
然后我们再来看一下爱奇艺的实现:
同样也是类似的,爱奇艺将整个屏幕作为影视的展示区,用户在看电影的时候眼中就只会有电影的内容,这样就不会被其他一些无关的东西所分心。
这才是沉浸式模式的真正含义,而所谓的什么沉浸式状态栏纯粹就是在瞎叫,完全都没搞懂“沉浸式” 这三个字是什么意思。
不过虽然听上去好像是很高大上的沉浸式效果,实际看上去貌似就是将内容全屏化了而已嘛。没错,android沉浸式模式的本质就是全屏化,不过我们今天的内容并不仅限于此,因为还要实现饿了么那样的状态栏效果。那么下面我们就开始来一步步学习吧。
隐藏状态栏
可以看到,有状态栏、actionbar、导航栏等。而打造沉浸式模式的用户体验,就是要将这些系统元素全部隐藏,只留下主体内容部分。
比如说我现在新建了一个空项目,然后修改布局文件中的代码,在里面加入一个imageview,如下所示:
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <imageview android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/bg" android:scaletype="centercrop" /> </relativelayout>
这里将imageview的宽和高都设置成match_parent,让图片充满屏幕。现在运行一下程序,效果如下图所示。
如果你将图片理解成游戏或者电影界面的话,那这个体验离沉浸式就差得太远了,至少状态栏和actionbar得要隐藏起来了吧?没关系,我们一步步进行优化,并且在优化中学习。
隐藏状态栏和actionbar的方式在4.1系统之上和4.1系统之下还是不一样的,这里我就不准备考虑4.1系统之下的兼容性了,因为过于老的系统根本就没有提供沉浸式体验的支持。
修改mainactivity中的代码,如下所示:
public class mainactivity extends appcompatactivity { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); view decorview = getwindow().getdecorview(); int option = view.system_ui_flag_fullscreen; decorview.setsystemuivisibility(option); actionbar actionbar = getsupportactionbar(); actionbar.hide(); } }
这里先调用getwindow().getdecorview()方法获取到了当前界面的decorview,然后调用它的setsystemuivisibility()方法来设置系统ui元素的可见性。其中,system_ui_flag_fullscreen表示全屏的意思,也就是会将状态栏隐藏。另外,根据android的设计建议,actionbar是不应该独立于状态栏而单独显示的,因此状态栏如果隐藏了,我们同时也需要调用actionbar的hide()方法将actionbar也进行隐藏。
现在重新运行一下程序,效果如下图所示。
这样看上去就有点沉浸式效果的模样了。
虽说这才是正统的沉浸式含义,但有些朋友可能想实现的就是饿了么那样的状态栏效果,而不是直接把整个系统状态栏给隐藏掉,那么又该如何实现呢?
其实也很简单,只需要借助另外一种ui flag就可以了,如下所示:
super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); if (build.version.sdk_int >= 21) { view decorview = getwindow().getdecorview(); int option = view.system_ui_flag_layout_fullscreen | view.system_ui_flag_layout_stable; decorview.setsystemuivisibility(option); getwindow().setstatusbarcolor(color.transparent); } actionbar actionbar = getsupportactionbar(); actionbar.hide();
首先需要注意,饿了么这样的效果是只有5.0及以上系统才支持,因此这里先进行了一层if判断,只有系统版本大于或等于5.0的时候才会执行下面的代码。
接下来我们使用了system_ui_flag_layout_fullscreen和system_ui_flag_layout_stable,注意两个flag必须要结合在一起使用,表示会让应用的主体内容占用系统状态栏的空间,最后再调用window的setstatusbarcolor()方法将状态栏设置成透明色就可以了。
现在重新运行一下代码,效果如下图所示。
可以看到,类似于饿了么的状态栏效果就成功实现了。
再声明一次,这种效果不叫沉浸式状态栏,也完全没有沉浸式状态栏这种说法,我们估且可以把它叫做透明状态栏效果吧。
隐藏导航栏
现在我们已经成功实现隐藏状态栏的效果了,不过屏幕下方的导航栏还比较刺眼,接下来我们就学习一下如何将导航栏也进行隐藏。
其实实现的原理都是一样的,隐藏导航栏也就是使用了不同的ui flag而已,修改mainactivity中的代码,如下所示:
super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); view decorview = getwindow().getdecorview(); int option = view.system_ui_flag_hide_navigation | view.system_ui_flag_fullscreen; decorview.setsystemuivisibility(option); actionbar actionbar = getsupportactionbar(); actionbar.hide();
这里我们同时使用了system_ui_flag_hide_navigation和system_ui_flag_fullscreen,这样就可以将状态栏和导航栏同时隐藏了。现在重新运行一下程序,效果如图所示。
这次看上去好像终于是完全全屏化了,但其实上这离真正的沉浸式模式还差得比较远,因为在这种模式下,我们触摸屏幕的任意位置都会退出全屏。
这显然不是我们想要的效果,因此这种模式的使用场景比较有限。
除了隐藏导航栏之外,我们同样也可以实现和刚才透明状态栏类似的效果,制作一个透明导航栏:
super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); if (build.version.sdk_int >= 21) { view decorview = getwindow().getdecorview(); int option = view.system_ui_flag_layout_hide_navigation | view.system_ui_flag_layout_fullscreen | view.system_ui_flag_layout_stable; decorview.setsystemuivisibility(option); getwindow().setnavigationbarcolor(color.transparent); getwindow().setstatusbarcolor(color.transparent); } actionbar actionbar = getsupportactionbar(); actionbar.hide();
这里使用了system_ui_flag_layout_hide_navigation,表示会让应用的主体内容占用系统导航栏的空间,然后又调用了setnavigationbarcolor()方法将导航栏设置成透明色。现在重新运行一下程序,效果如下图所示。
真正的沉浸式模式
虽说沉浸式导航栏这个东西是被很多人误叫的一种称呼,但沉浸式模式的确是存在的。那么我们如何才能实现像海岛奇兵以及爱奇艺那样的沉浸式模式呢?
首先你应该确定自己是否真的需要这个功能,因为除了像游戏或者视频软件这类特殊的应用,大多数的应用程序都是用不到沉浸式模式的。
当你确定要使用沉浸式模式,那么只需要重写activity的onwindowfocuschanged()方法,然后加入如下逻辑即可:
public class mainactivity extends appcompatactivity { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); } @override public void onwindowfocuschanged(boolean hasfocus) { super.onwindowfocuschanged(hasfocus); if (hasfocus && build.version.sdk_int >= 19) { view decorview = getwindow().getdecorview(); decorview.setsystemuivisibility( 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 | view.system_ui_flag_immersive_sticky); } } }
沉浸式模式的ui flag就这些,也没什么好解释的,如果你需要实现沉浸式模式,直接将上面的代码复制过去就行了。需要注意的是,只有在android 4.4及以上系统才支持沉浸式模式,因此这里也是加入了if判断。
另外,为了让我们的界面看上去更像是游戏,这里我将mainactivity设置成了横屏模式:
<activity android:name=".mainactivity" android:screenorientation="landscape"> ... </activity>
这样我们就实现类似于海岛奇兵和爱奇艺的沉浸式模式效果了,如下图所示。
可以看到,界面默认情况下是全屏的,状态栏和导航栏都不会显示。而当我们需要用到状态栏或导航栏时,只需要在屏幕顶部向下拉,或者在屏幕右侧向左拉,状态栏和导航栏就会显示出来,此时界面上任何元素的显示或大小都不会受影响。过一段时间后如果没有任何操作,状态栏和导航栏又会自动隐藏起来,重新回到全屏状态。
这就是最标准的沉浸式模式。
android 动态控制状态栏显示和隐藏的方法实例
android想要应用运行时全屏有一种方法是在activity的oncreat方法中加入如下代码:getwindow().setflags(windowmanager.layoutparams.flag_fullscreen,
并且需要在setcontentview()之前,否则无效过。从这么多的苛刻条件可以看出这种方法无法满足动态控制。
windowmanager.layoutparams.flag_fullscreen);
下面的方法可以满足这个需要。调用view的 setsystemuivisibility()
方法,其参数如下:
- view.system_ui_flag_fullscreen, //全屏,状态栏和导航栏不显示
- view.system_ui_flag_hide_navigation, //隐藏导航栏
- view.system_ui_flag_layout_fullscreen, //全屏,状态栏会盖在布局上
- view.system_ui_flag_layout_hide_navigation,
- view.system_ui_flag_layout_stable,
- view.system_ui_flag_low_profile,
- view.system_ui_flag_visible, //显示状态栏和导航栏
- view.system_ui_layout_flags
android colorprimary colorprimarydark coloraccent
android design theme color
<style name="apptheme.noactionbar"> <!--状态栏颜色--> <item name="colorprimarydark">@color/colorprimarydark</item> <!--控制各个控件被选中时的颜色--> <item name="coloraccent">@color/coloraccent</item> <!--页面背景色--> <item name="android:windowbackground">@color/windowbackg</item> <!--底部导航栏颜色--> <item name="android:navigationbarcolor">@color/navigationcolor</item> <!--appbar背景色--> <item name="android:colorprimary">@color/colorprimary</item> <!--toolbar上的title颜色--> <item name="android:textcolorprimary">@color/textcolorprimary</item> <!--各个控制控件的默认颜色--> <item name="android:colorcontrolnormal">@color/colorcontrolnormal</item> </style>
android design theme color 保存在res/values/styles.xml下
<resources> <!-- base application theme. --> <style name="apptheme" parent="theme.appcompat.light.darkactionbar"> <!-- customize your theme here. --> <item name="colorprimary">@color/colorprimary</item> <item name="colorprimarydark">@color/colorprimarydark</item> <item name="coloraccent">@color/coloraccent</item> </style> </resources>
color rgb值保存在res/values/colors.xml下
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorprimary">#3f51b5</color> <color name="colorprimarydark">#000000</color> <color name="coloraccent">#ffffff</color> </resources>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。