总结系列-一文搞懂沉浸式状态栏

ZhangQiang- ZhangQiang-     2022-12-05     736

关键词:

近期做到与状态栏相关一些需求,网上关于沉浸式状态栏的文章有很多,基本上都先讲一堆概念,然后接着推出一个自己写的轮子,这类轮子面对很多不同场景的情况不能百分之百满足使用需求,过度地使用轮子也往往会让开发者不了解代码到底是怎么实现沉浸式的,基于之上,参考一些文章及自身经验总结此篇文章. 需要注意的是,并没有沉浸式状态栏这一概念,只有沉浸式模式和透明状态栏的概念。 (注: 此篇非原理,非解决方案封装类,偏于实用与查阅对比,底部参考链接有GitHub上的轮子供参考)     实现沉浸式状态栏主要跟以下四个Api相关:
  • View#setSystemUiVisibility()
  • Window#addFlags()
  • View#setFitsSystemWindows
  • Window#setStatusBarColor()
 

View#setSystemUiVisibility()及其各种Flags

int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;        getWindow().getDecorView() .setSystemUiVisibility(uiOptions) setSystemUiVisibility (int visibility)传入的实参类型如下:( 基本上可以定义为状态栏和Activity之间的位置关系 )  
WindowManager.LayoutParams.FLAG_FULLSCREEN 隐藏状态栏(在代码中设置)
View.SYSTEM_UI_FLAG_VISIBLE 14   系统默认 显示状态栏和导航栏   状态栏和Activity共存,Activity不全屏显示。也就是应用平常的显示画面
View. SYSTEM_UI_FLAG_FULLSCREEN    16  状态栏隐藏,效果同设置WindowManager.LayoutParams.FLAG_FULLSCREEN ,  Activity全屏显示,且状态栏被覆盖掉 视图全屏并隐藏状态栏,当用户交互时(如下滑状态栏)会恢复隐藏的状态栏(例子:电子书阅读) 缺点: 进入Activity会产生一个从非全屏到全屏的闪动效果 ,( 恢复状态栏视图下移 )   可以使用 SYSTEM_UI_FLAG_LAYOUT_FULLSCREE 标志,让应用的内容区域显示在状态栏的后面,还可以配合 SYSTEM_UI_FLAG_LAYOUT_STABLE 标志使用,让布局保持稳定
   
View. SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 16   视图延伸至状态栏区域,状态栏上浮于视图之上   (视图全屏且不会产生闪动,状态栏会覆盖在视图上面) Activity全屏显示,但是状态栏不会被覆盖掉,而是正常显示,只是Activity顶端布局会被覆盖住 可以配合 SYSTEM_UI_FLAG_LAYOUT_STABLE 标志使用,让布局保持稳定
View. SYSTEM_UI_FLAG_HIDE_NAVIGATION     隐藏导航栏
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION      window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or                     View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or                     View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or                     View.SYSTEM_UI_FLAG_FULLSCREEN or                     View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN ↑效果:隐藏状态栏/导航栏 16    视图延伸至导航栏区域导航栏上浮于视图之上   * 按照一个通用的规则,在隐藏导航栏的时候,一般也需要隐藏状态栏 * 通过这种方式隐藏导航栏和状态栏之后, 触摸屏幕的任何区域,导航栏和状态栏都会重新出现且不会再消失,如果想让导航栏和状态栏消失,则需要手动重新设置 UI flag * 如果想让内容区域出现在导航栏的后面,则需要配合使用 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 标志,并且最好配合使用 SYSTEM_UI_FLAG_LAYOUT_STABLE 使布局保持稳定
View.SYSTEM_UI_FLAG_LAYOUT_STABLE   16   保持整个View稳定, 常和控制System UI悬浮, 隐藏的Flags共用, 使View不会因为System UI的变化而重新layout 保持View Layout不变, 隐藏状态栏或者导航栏后,View不会拉伸。 * 使视图稳定,当使用fitSystemWindows()需要视图稳定,一般和View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN联用
View.SYSTEM_UI_FLAG_IMMERSIVE      (需要联用,已被SYSTEM_UI_FLAG_IMMERSIVE_STIKY取代) 19   只有当设置了SYSTEM_UI_FLAG_HIDE_NAVIGATION才起作用。如果没有设置,任意的View相互动作都退出SYSTEM_UI_FLAG_HIDE_NAVIGATION模式。如果设置就不会退出。 沉浸模式, 隐藏状态栏和导航栏, 并且在第一次会弹泡提醒, 并且在状态栏区域滑动可以呼出状态栏(这样系统会清除之前设置的View.SYSTEM_UI_FLAG_FULLSCREEN或View.SYSTEM_UI_FLAG_HIDE_NAVIGATION标志)。使之生效,需要和View.SYSTEM_UI_FLAG_FULLSCREEN,View.SYSTEM_UI_FLAG_HIDE_NAVIGATION中的一个或两个同时设置。
View. SYSTEM_UI_FLAG_IMMERSIVE_STIKY       (需要联用)     效果:沉浸式模式 19   粘性沉浸模式,只有当设置了SYSTEM_UI_FLAG_FULLSCREEN或者SYSTEM_UI_FLAG_HIDE_NAVIGATION时起作用,当使用View.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)联用时视图全屏,当用户产生交互时(如下滑状态栏) 不会恢复状态栏,只会以半透明的方式覆盖在视图上面并在一定时间内自动消失 如果没有设置,任意的View相互动作都退出SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION模式。 与上面唯一的区别是, 呼出隐藏的状态栏后不会清除之前设置的View.SYSTEM_UI_FLAG_FULLSCREEN或View.SYSTEM_UI_FLAG_HIDE_NAVIGATION标志,一段时间后将再次隐藏系统栏)   如果设置了 View.OnSystemUiVisibilityChangeListener 监听器,SYSTEM_UI_FLAG_IMMERSIVE 会触发 OnSystemUiVisibilityChangeListener 监听器,但是 SYSTEM_UI_FLAG_IMMERSIVE_STICKY 不会触发 OnSystemUiVisibilityChangeListener 监听器
View.SYSTEM_UI_FLAG_LOW_PROFILE 效果:淡化状态栏/导航栏 14  低调模式, 会隐藏不重要的状态栏图标  状态栏上一些图标显示会被隐藏 , 且有 淡化状态栏和导航栏的效果 一旦用户触摸 StatusBar 和 NavigationBar 相关区域,系统便清除掉了flag
View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR   Android6.0系统以上增加的属性,设置了这个属性,状态栏会以与状态栏 背景颜色兼容的模式绘制(如果当前的状态栏颜色是浅色,那么就有可能造成状态栏上的图标看不清了,但是如果你设置这个属性以后,状态栏的图标就会以深色绘制) int vis = decorView.getSystemUiVisibility(); if (isLightMode)     vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; else     vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;  
注:
  • 一旦这些标志位被清除,则需要重新设置让状态栏隐藏,可以通过监听状态栏和导航栏的可见性,判断状态栏和导航栏是否可见
  • 在不同的位置设置 UI flag 是有区别的。比如,如果在 onCreate() 方法中隐藏状态栏,那当用户按下 Home 键的时候,状态栏重新显示,再打开应用重新回到这个 Activity 的时候,用户可以看到状态栏, 因为这时不会调用 onCreate() 方法, 如果在 onResume() 或者 onWindowFocusChanged() 就可以避免上面这种情况
  • 只有当调用 setSystemUiVisibility() 的 View 是可见的时候,setSystemUiVisibility() 方法才会起作用
  • 界面的切换会导致 setSystemUiVisibility() 的设置失效
  • 可以通过  View.OnSystemUiVisibilityChangeListener  为该  View  设置状态栏和导航栏可见性的监听
     

Window.addFlags()及其各种Flags ( WindowManager.LayoutParams相关属性)

FLAG_TRANSLUCENT_STATUS   对应↓: <item name= "android:windowTranslucentStatus" > true </item> * Android4.4系统增加的属性,它会使状态栏透明透明并且自动执行View.SYSTEM_UI_FLAG_LAYOUT_STABLE和View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
FLAG_FULLSCREEN <item name=" android:windowFullscreen">true</item> 视图全屏并隐藏状态栏,效果相当于View.SYSTEM_UI_FLAG_FULLSCREEN+View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY,并且视图稳定(不会因为系统控件的变化(如输入法),而重新布局)
FLAG_FORCE_NOT_FULLSCREEN 重写了FLAG_FULLSCREEN并 强制显示状态栏(没什么用)
FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS Android5.0系统以上支持,如果设置了该属性,系统栏(状态栏和导航栏)将以透明背景绘制,并且该窗口中的相应区域将填充setStatusBar()和setNavigationBarColor()中设置的颜色
FLAG_TRANSLUCENT_NAVIGATION     对应↓: <item name= "android:windowTranslucentNavigation" > true </item> 隐藏虚拟键(导航栏)  
系统在我们添加windowTranslucentStatus和windowTranslucentNavigation属性时候,会自动为我们增加View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION属性。 那要怎么解决我们的布局会被拓展到系统栏后面的效果。在layout.xml增加android:fitsSystemWindows="true"即可。  

View#setFitsSystemWindows

此方法只有当设置SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN或者SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION才有有效,当窗口发生变化时,View需要调整自身内容以适应窗口的变化, 你可以理解为当和 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN一起联用的时候,是给View加了个bottomTop属性,宽度填充视图,高度就是状态栏的高度; 当和 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION一起联用的时候,是给View加了个bottomBottom属性,宽度填充视图,高度就是导航栏的高度,建议给布局的顶层ViewGroup使用    

Window#setStatusBarColor()

android 5.0系统及以上开始支持,设置状态栏的颜色,为了使这个状态有效 必须要设置FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS而且不 能设置FLAG_TRANSLUCENT_STATUS(window. clearFlags )      

实现沉浸式状态栏的具体套路

实现沉浸式状态栏分为三个阶段,
  • Android4.4~Android5.0以下;
  • Android5.0~Android6.0以下;
  • Android6.0以上;
  背景是一张图片 颜色跟标题栏一致
Android4.4~5.0 window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);   FLAG_TRANSLUCENT_STATUS这个属性会让状态栏以白色绘制,同时还会执行SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_STABLE这样就会让状态栏浮在图片的上面,这样就形成了沉浸式的效果   颜色跟标题栏一致的情况 ======> 这个阶段实现的套路是,先制造一个假的View背景颜色跟标题栏的颜色一致,高度跟状态栏的高度一致,添加到顶层DecorView上面,然后让Android的最顶层的内容布局调用setFitsSystemWindows空出来状态栏的高度,最后调用FLAG_TRANSLUCENT_STATUS这个属性即可,让状态栏透明并浮在假View上   View statusView = new View(activity); ViewGroup.LayoutParams statusViewLayoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams. MATCH_PARENT , getStatusBarHeight (activity)); ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); decorView.addView(statusView, statusViewLayoutParams); ViewGroup rootView = decorView.findViewById(Window. ID_ANDROID_CONTENT ); if (rootView != null ) rootView.setFitsSystemWindows( true ); activity.getWindow().addFlags(WindowManager.LayoutParams. FLAG_TRANSLUCENT_STATUS )
Android5.0~6.0 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);             activity.getWindow().setStatusBarColor(Color.TRANSPARENT);             activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);             activity.getWindow()                     .getDecorView()                     .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);   把状态栏的颜色设置成透明,同时让状态栏浮在视图上面且保持稳定,这样图片就会顶到视图的顶部,因此就实现了沉浸式的效果   方式一:直接给状态栏设置对应的颜色 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);             activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);             activity.getWindow().setStatusBarColor(color);   方式二:给状态栏设置透明色并让状态栏浮在视图顶层,配合setFitsSystemWindows() activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);             activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);             activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);             activity.getWindow().setStatusBarColor(Color.TRANSPARENT);   toolBar.setFitsSystemWindows(true);//这里根据自己的布局情况
Android6.0 在5.0~6.0阶段发现了一个小问题,就是当我们要给状态栏设置的颜色是白色或者浅色的时候,因为默认的状态上图标的颜色是白色就会造成看不清的现象,如下图所示 为了避免这种情况,Android系统在6.0的时候增加了一个属性SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,这里不再赘述,使用了它以后,状态栏上的图标文字就会默认使用黑色绘制。   activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);             activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);             activity.getWindow().setStatusBarColor(color);             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)                 activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);               

透明状态栏和导航栏示例

// setContentView之前 private fun transparentingNavigationbar()         var uiFlag = 0         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)             uiFlag = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or                     View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or                     View.SYSTEM_UI_FLAG_FULLSCREEN or                     View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)             uiFlag = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or uiFlag                  window.decorView.systemUiVisibility = uiFlag         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)             window.statusBarColor = Color.TRANSPARENT             window.navigationBarColor = Color.TRANSPARENT                
  • 除了可以设置状态栏和导航栏为透明,还可以设置为其他颜色
  • 只可以在 Android 5.0(API level 21)及以上的 Android 版本中设置状态栏和导航栏的颜色

版本要求

效果 版本要求
淡化状态栏和导航栏 Version >= 14
隐藏状态栏 全部版本
隐藏导航栏 Version >= 16
沉浸式模式 Version >= 19
透明状态栏 Version >= 21
   
参考:  状态栏及导航栏相关知识小结 沉浸式状态栏全面解析 Android关于沉浸式状态栏总结(4.4-6.0以上实现) 全屏、沉浸式、fitSystemWindow使用及原理分析 随手记Android沉浸式状态栏的踩坑之路(2017) GitHub封装示例1(8.4k)   ;    github util封装示例(0.3k) ;  Android 沉浸式状态栏(utils封装)    Android windowTranslucentStatus属性源码分析  Activity 全屏,沉浸式模式分析及SystemBar 监听 (2016) Android沉浸式状态栏解析 (郭霖2016) 全屏沉浸模式ImmersiveMode ( SYSTEM_UI_FLAG_IMMERSIVE) Android 自动隐藏虚拟按键和沉浸式状态栏

android透明状态栏和沉浸式的实现

...,而所谓的什么沉浸式状态栏纯粹就是在瞎叫,完全都没搞懂“沉浸式”这三个字是什么意思。不过虽然听上去好像是很高大上的沉浸式效果,实际看上去貌似就是将内容全屏化了而已嘛。没错,Android沉浸式模式的本质就是全... 查看详情

android沉浸式状态栏(代码片段)

...章目录前言一、沉浸式状态栏二、改变标题和状态栏颜色总结前言4-20分享提示:以下是本篇文章正文内容,下面案例可供参考先来看下效果图(夜神模拟器和真机有点差别,我不会搞gif动图,就勉强看下吧):一、沉浸式状态... 查看详情

android实现沉浸式全屏(代码片段)

前言本文总结Android实现沉浸式全屏的实现方式。实现沉浸式全屏在一些需要全屏显示的场景下,比如玩游戏、看横屏视频的时候,内容全屏,占满窗口的体验会让用户更加沉浸到对内容的消费中,带来好的用户体验。沉浸式显... 查看详情

android---沉浸式状态栏(代码片段)

Android—沉浸式状态栏我们的征程是星辰大海,而非人间烟尘文章目录Android---沉浸式状态栏去掉标题栏效果引入依赖沉浸状态栏颜色沉浸状态栏图片去掉标题栏首先去掉对应主题下面的Android自带的ActionBar,只需要在对应... 查看详情

沉浸式状态栏

知识来源:https://zhidao.baidu.com/question/1989575143165411427.html  (1)内容应用到状态栏(360流量允许拖动到状态栏的效果)Windowwindow=getWindow();window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,WindowManager. 查看详情

android沉浸式状态栏(代码片段)

...章目录前言一、沉浸式状态栏二、改变标题和状态栏颜色总结前言4-20分享提示:以下是本篇文章正文内容,下面案例可供参考先来看下效果图(夜神模拟器和真机有点差别,我不会搞gif动图,就勉强看下吧):一、沉浸式状态... 查看详情

沉浸式状态栏与导航条

...黑色,而是可以定制的颜色。  国内将状态栏变色叫做沉浸式状态栏,时间久了,叫的人多了,大家就不再深究,默认了这种叫法。  查看详情

知识教程|优化状态栏沉浸式效果

沉浸式状态栏是让开发者尤其是Android开发者很头疼的问题,耗费开发者很多精力去校验代码在各个系统版本、各个机型上是否有效,今天这篇教程就跟大家分享优化初始化状态栏沉浸式效果的方法。使用APICloud时,参照社区源码... 查看详情

沉浸式状态栏的三种实现方式

沉浸式算是目前Android行业比较流行的一种App设计风格,将菜单栏北京设置为导航栏的颜色,感觉顶部状态栏像是被入侵了一样,因此称为沉浸式菜单栏。本文将介绍三种方式去实现沉浸式状态栏。  Google从androidkitkat(Androi... 查看详情

android沉浸式状态栏(代码片段)

在使用沉浸式状态栏时需要注意设置的沉浸颜色为白色还是其他深色的区别1.状态栏字体图标黑色(深色)//5.0以上系统状态栏透明if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP)Windowwindow=getWindow();window.clearFlags(WindowMan... 查看详情

沉浸式状态栏设置状态栏颜色

方式一:使用系统API这个特性是andorid4.4支持的,最少要api19才可以使用。1、隐藏标题栏等在代码中设置        requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题栏        查看详情

沉浸式状态栏框架-systembartint(代码片段)

为什么要使用沉浸式状态栏呢?--为了用户体验。因为有的app界面的风格都是差不多的,比如支付宝,用的蓝色调风格,为了让状态栏看起来不那么突兀,我们可以使用沉浸式状态栏。沉浸式状态栏在游戏app中... 查看详情

沉浸式状态栏框架-systembartint(代码片段)

为什么要使用沉浸式状态栏呢?--为了用户体验。因为有的app界面的风格都是差不多的,比如支付宝,用的蓝色调风格,为了让状态栏看起来不那么突兀,我们可以使用沉浸式状态栏。沉浸式状态栏在游戏app中... 查看详情

java状态栏工具类,显示隐藏状态栏,设置状态栏颜色,沉浸式,透明状态栏(代码片段)

查看详情

android--------沉浸式状态栏immersionbar3.0(代码片段)

沉浸式状态栏我一直在使用的一个库ImmersionBar,非常不错,现在都3.0了android4.4以上沉浸式状态栏和沉浸式导航栏管理,适配横竖屏切换、刘海屏、软键盘弹出等问题,可以修改状态栏字体颜色和导航栏图标颜色&#x... 查看详情

android--------沉浸式状态栏immersionbar3.0(代码片段)

沉浸式状态栏我一直在使用的一个库ImmersionBar,非常不错,现在都3.0了android4.4以上沉浸式状态栏和沉浸式导航栏管理,适配横竖屏切换、刘海屏、软键盘弹出等问题,可以修改状态栏字体颜色和导航栏图标颜色&#x... 查看详情

沉浸式导航栏及状态栏系统图标颜色的改变

最近研究沉浸式导航栏,上网看了好多,差不多实现都是一样的。。。。代码如下: //透明状态栏getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//透明导航栏getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIG 查看详情

沉浸式状态栏

  我们知道IOS上的应用。状态栏的颜色总能与应用标题栏颜色保持一致,用户体验非常不错。那安卓能否够呢?若是在安卓4.4之前,答案是否定的,但在4.4之后,谷歌同意开发人员自己定义状态栏背景颜色啦,这是个不错... 查看详情