Android系统栏相关(SystemBar)
来源:互联网 发布:linux里sort怎么用 编辑:程序博客网 时间:2024/06/05 06:16
Android系统栏相关(SystemBar)
基础知识,仅作备忘
SystemBar是用来展示通知、表现设备状态和完成设备导航的屏幕区域。主要包括状态栏(1:status bar)和导航栏(2:navigation bar)。借用官方的图,如下所示,我们可以根据需要对SystemBar进行一些操作,满足自己的需求。
淡化SystemBar (View.SYSTEM_UI_FLAG_LOW_PROFILE)
从API14,即4.0开始,我们可以借助View.SYSTEM_UI_FLAG_LOW_PROFILE
来淡化SystemBar,以突出内容区域。
当你使用这个方法的时候,内容区域的大小并不会发生变化,只是系统栏的图标会收起来。一旦用户触摸状态栏或者是导航栏的时候,这两个系统栏就又都会完全显示(无透明度)。
这种方法的优势是SystemBar仍然可见,但是它们的细节被隐藏掉了,因此可以在不牺牲快捷访问系统栏的情况下创建一个沉浸式的体验。
设置代码:
mView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
如图所示:
一旦用户触摸到状态栏或者是系统栏,这个标签就会被清除,使系统栏重新显现(无透明度)。在标签被清除的情况下,如果你想重新淡化系统栏就必须重新设定这个标签。
或者我们也可以通过代码直接清除该标志:
mView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
如图所示:
View.SYSTEM_UI_FLAG_VISIBLE
表示请求系统显示SystemBar.
隐藏SystemBar
在Api15及其之下,可以通过设置Window的Flag标志来达到全屏目的,一般两个标志位同时设置: getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
WindowManager.LayoutParams.FLAG_FULLSCREEN
设置全屏模式,隐藏窗口装饰。除了动态设置外,还可以在主题中设置windowFullscreen属性来达到全屏目的。
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
设置了FLAG_LAYOUT_IN_SCREEN之后,可以拥有与启用FLAG_FULLSCREEN相同的屏幕区域。这个方法防止了状态栏隐藏和显示时,内容区域的大小变化。但是此时,状态栏应该是在压在内容区域之上,所以需要自己处理布局,防止状态栏遮盖重要的内容区域。
当你设置WindowManager标签之后(无论是通过Activity主题还是动态设置),这个标签都会一直生效直到你清除它。这点和View.setSystemUiVisibility设置有本质的区别。
在Api16及其之上,可以通过View.setSystemUiVisibility来设置。该方法可以用来控制SystemBar的显示和隐藏,下面简单介绍下其可以设置的Flag:
最重要的两个Flag:
View.SYSTEM_UI_FLAG_IMMERSIVE
Api19
(控制SYSTEM_UI_FLAG_HIDE_NAVIGATION flag是否能被用户交互行为所清除)If this flag is not set, SYSTEM_UI_FLAG_HIDE_NAVIGATION will be force cleared by the system on any user interaction。如果没有设置该flag,那么任何用户交互行为都会清除SYSTEM_UI_FLAG_HIDE_NAVIGATION flag,从而导致导航栏重新显示出来。
Since this flag is a modifier for SYSTEM_UI_FLAG_HIDE_NAVIGATION, it only has an effect when used in combination with that flag.
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
Api19
(控制SYSTEM_UI_FLAG_FULLSCREEN和SYSTEM_UI_FLAG_HIDE_NAVIGATION flag是否能被用户交互行为所清除)If this flag is not set, SYSTEM_UI_FLAG_HIDE_NAVIGATION will be force cleared by the system on any user interaction, and SYSTEM_UI_FLAG_FULLSCREEN will be force-cleared by the system if the user swipes from the top of the screen.如果没有设置该flag,那么任何用户交互行为都会清除SYSTEM_UI_FLAG_HIDE_NAVIGATION flag,同时从边缘区域向内滑动则会清除SYSTEM_UI_FLAG_FULLSCREEN flag,从而导致状态栏和导航栏重新显示出来。
When system bars are hidden in immersive mode, they can be revealed temporarily(临时显示) with system gestures, such as swiping from the top of the screen. These transient system bars will overlay app’s content, may have some degree of transparency, and will automatically hide after a short timeout.这种模式下的SystemBar,是半透明的,在显示出来后,隔一段时间会自动隐藏,不会清除SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN flag。
Since this flag is a modifier for SYSTEM_UI_FLAG_FULLSCREEN and SYSTEM_UI_FLAG_HIDE_NAVIGATION, it only has an effect when used in combination with one or both of those flags.
若仅仅设置了View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,那么用户点击内容区域的任何位置都会唤出SystemBar,清除SYSTEM_UI_FLAG_FULLSCREEN和SYSTEM_UI_FLAG_HIDE_NAVIGATION标志位。这不是真正的沉浸式,因为在这种全屏模式下,用户无法和内容区域进行交互。
若是设置了
View.SYSTEM_UI_FLAG_IMMERSIVE
| View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,那么用户只有在从边缘区域向内滑动时,才能让SystemBar显示。这算是沉浸式了,用户可以和内容区域直接交互了。只有特定的操作(从边缘区域向内滑动),才会清除标志位,重新唤出SystemBar。若是设置了
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,那么唤出SystemBar的方式和SYSTEM_UI_FLAG_IMMERSIVE
相同,只不过唤出的SystemBar是半透明的,淡化的SystemBar,并且不再会清除SYSTEM_UI_FLAG_FULLSCREEN和SYSTEM_UI_FLAG_HIDE_NAVIGATION标志位,在几秒后,SystemBar又会重新隐藏。这个算不算沉浸式那,算吧。
除了
SYSTEM_UI_FLAG_IMMERSIVE_STICKY
之外,其他两种模式在SystemBar的可见性发生改变时,都可以通过View.OnSystemUiVisibilityChangeListener
监听器来获得通知。请注意,若带有
SYSTEM_UI_FLAG_IMMERSIVE_STICKY
标签,则不会触发任何的监听器,因为在这种模式下展示的SystemBar是处于暂时(transient)的状态。实际使用中,需要根据具体需求,来选择三种不同的用户交互模式。
其他的Flag如下所示:
关于WindowManager.LayoutParams.FLAG_FULLSCREEN和View.SYSTEM_UI_FLAG_FULLSCREEN
两者达到的目标效果是一致的,都可以隐藏status bar,但存在着一些区别:
1. FLAG_FULLSCREEN从Api1开始就有了,不存在版本兼容问题;而SYSTEM_UI_FLAG_FULLSCREEN则是从Api16开始才有的,存在着兼容问题。
2. FLAG_FULLSCREEN是通过Window添加到对应Window的布局参数WindowManager.LayoutParams中;而SYSTEM_UI_FLAG_FULLSCREEN则是作用某个可见的View。
3. 最重要的区别:FLAG_FULLSCREEN的作用是持久的,一经设置,永久有效(除非主动清除clearFlags
);而SYSTEM_UI_FLAG_FULLSCREEN则是临时性的,通过用户交互操作,可以直接清除标志。
4. 若设置FLAG_FULLSCREEN,需要单独处理ActionBar;而若ActionBar设置了Window.FEATURE_ACTION_BAR_OVERLAY,那么再设置SYSTEM_UI_FLAG_FULLSCREEN时,会同时隐藏ActionBar。
关于View.setFitsSystemWindows和View.fitSystemWindows
当我们通过设置上述Flag,来让Content View延伸到SystemBar时,SystemBar会覆盖在Content View之上,这会带来一些不好的体验。
Android本身给我们提供了解决方案,即调用View.setFitsSystemWindows
或者设置属性android:fitsSystemWindows="true"
。这样,Android系统会调用View.fitSystemWindows
来修复SystemBar覆盖Content View的情况。简单来说,fitsSystemWindow="true"
会使得屏幕上的Content View位于状态栏下方与导航栏上方的区域。
View.fitSystemWindows方法会接收Rect类型的参数,表示Current content insets of the window。fitSystemWindows方法最终会将Rect参数设置到当前View的Padding中,已达到调整Content View的内边距,保证Content View不会被SystemBar覆盖的目的。因此,我感觉Rect.top应该表示Status Bar的高度(不包含ActionBar的情况下),Rect.bottom应该对应Navigation Bar的高度,下面会验证下。
View.fitSystemWindows修改View Padding的核心代码如下所示,
View.fitSystemWindows -> View.internalSetPadding:
//left、top、right和bottom即为Rect参数对应的值if (mPaddingLeft != left) { mPaddingLeft = left; }if (mPaddingTop != top) { mPaddingTop = top; }if (mPaddingRight != right) { mPaddingRight = right; }if (mPaddingBottom != bottom) { mPaddingBottom = bottom; }
做了一下实验,主要是验证下fitSystemWindows方法中的Rect参数的取值和SystemBar高度的关系:
设置SystemBar的代码如下所示:
//在mMyRelativeLayout中重写fitSystemWindows,查看Rect参数mMyRelativeLayout.setFitsSystemWindows(true);//设置Flag,控制SystemBar的可见性mMyRelativeLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE)
获取状态栏和导航栏的高度:
//获取状态栏高度public static int getStatusBarHeight(Context context) { int result = 0; Resources resources = context.getResources(); int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = resources.getDimensionPixelSize(resourceId); } Log.d("leon", "getStatusBarHeight = " + result); return result; }//获取导航栏的高度 public static int getNavigationBarHeight(Context context) { int result = 0; Resources resources = context.getResources(); int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android"); if (resourceId > 0) { result = resources.getDimensionPixelSize(resourceId); } Log.d("leon", "getNavigationBarHeight = " + result); return result; }
然后,对比Rect的取值和SystemBar的高度:
//rect参数取值insets = Rect(0, 50 - 0, 96)//status bar的高度getStatusBarHeight = 50//navigation bar的高度getNavigationBarHeight = 96//修改后的mMyRelativeLayout的topPaddingtopPadding = 50//修改后的mMyRelativeLayout的bottomPaddingbottomPadding = 96
从上述结果对比来看,验证了我们之前的猜测,参数Rect的取值和状态栏和导航栏的高度相关。
此外,如果fitSystemWindows方法的默认行为无法满足我们的需求,那么我们可以重写该方法,参考Rect的取值,自己决定如何修改mMyRelativeLayout的的padding.
从Api20开始,fitSystemWindows方法被废弃了,提供了新的方法dispatchApplyWindowInsets(WindowInsets)、onApplyWindowInsets(WindowInsets) 和setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)来实现类似功能,这部分后续再看下吧。
参考:
1. android-training-course-in-chinese之管理系统UI
2. 官方文档
3. 透明状态栏和透明导航栏
4. 沉浸模式
- Android系统栏相关(SystemBar)
- Android--操作系统的SystemBar
- Android 状态栏(SystemBar)颜色改变
- ANDROID 隐藏 任务栏 systemui systembar 全屏显示
- ANDROID 隐藏 任务栏 systemui systembar 全屏显示
- Android平板4.1隐藏SystemBar(状态栏?~)
- ANDROID 隐藏 任务栏 systemui systembar 全屏显示
- Android - 开发实例(14):透明SystemBar
- Android - 开发实例(15):变色SystemBar
- ANDROID 隐藏 任务栏 systemui systembar 全屏显示
- android SystemBar 安卓状态栏工具类
- 如何在Android 4.0 ICS中禁用StatusBar | SystemBar | 状态栏
- Android简单的获取SystemBar,StatusBar,NavigationBar的高度
- Android简单的获取SystemBar,StatusBar,NavigationBar的高度
- android 系统属性相关
- android获取系统相关
- 【android】系统分区相关
- Android短信系统相关
- 【Unity】UGUI中RectTransform中Top和Bottom的设置,宽和高的设置,以及postion和锚点的设置
- EM算法简单理解
- 安卓:service,AID通信,有服务端和客户端的
- C++进阶学习——单例模式的实现
- 黑马程序员----C 语言学习笔记之结构体数组,指针,嵌套的使用
- Android系统栏相关(SystemBar)
- 证明方法------杂谈
- DoTween 一:< SetEase —— 渐变曲线 >
- iOS开发工具——网络封包分析工具Charles
- android系统通讯录源码--显示联系人添加长按事件监听
- 黑马程序员——C语言基础---结构体2
- 队列的链式实现
- 京东面试软件测试工程师问题总结
- 高效学习OpenGL之图像glDrawPixels(),glCopyPixels(),glReadPixels()