[Android] 状态栏的一些认识
前段时间遇到几个关于状态栏的问题,又了解了一下状态栏相关的知识,现在做一下记录。
本文地址:http://www.cnblogs.com/rossoneri/p/4316343.html
前戏和问题
首先一般的设备都含有两个bar:顶部的状态栏(statusbar)和底部的工具栏(NavigationBar),关于这两个Bar我最初的认识在于之前的文章:
[Android]获取系统顶部状态栏(StatusBar)与底部工具栏(NavigationBar)的高度
通过之前文章的方法就可以获取屏幕高度,来对界面进行一番设计。但后来我突然发现了一个棘手的新问题,我遇到了这么一个蛋疼的界面:
它竟然把两个Bar合并到一起了。。。我去。。
因为之前的一个控件设计是考虑了上下两条Bar的高度,然后相对顶部工具栏来进行计算,结果遇上这么个屏幕,界面的控件纵向显示就出现了小的偏移,大概30dp左右。
好了,问题来了,那就着手解决吧。
思考和解决
既然你把上下的Bar合并在一起,那么原来顶部的statusbar是隐藏了么?
我先用前文提到的方法试试输出顶部状态栏的高度,结果得到一个高度,是25。嗯,跟我看到的大概30dp高度差不多,也就是说顶部状态栏高度是存在的。那是被隐藏了么?
想知道这个,就需要找找Android是否有提供一个获取statusbar显示状态的方法。查了查API,找到了一个方法:
int n = mActivity.getWindow().getDecorView().getSystemUiVisibility();
结果得到 n = 0
看了看 0 的含义:
/** * Special constant for {@link #setSystemUiVisibility(int)}: View has * requested the system UI (status bar) to be visible (the default). * * @see #setSystemUiVisibility(int) */ public static final int SYSTEM_UI_FLAG_VISIBLE = 0;
也就是说顶部的statusbar是默认的可见状态。WTF,我明明看不见了,你竟然说还是默认的显示状态。好吧,难道这个statusbar移到底部合并 显示 了吗?但高度不对呀。
带着疑问,我又试着输出底部工具栏高度,得到了48。跟之前的设备一样,底部的高度没有变。
得,说到底,两条Bar的高度是都可以获取到的,而且值和正常的一样,虽然顶部的看不见,但状态还是默认的可见的,显示成这个样式是系统定制时设定的。姑且这么理解吧。
既然底部的工具栏高度没有变化,我的控件就重新以底部为参照来计算好了。用这个方法,暂且解决了控件显示位置的问题。
拓展知识
经过上面的问题,好歹是解决了眼前的bug。趁着看到这一块,我就又多了解了一下表示bar状态的几个标识:
1 /** 2 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3 * requested the system UI (status bar) to be visible (the default). 4 * 5 * @see #setSystemUiVisibility(int) 6 */ 7 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 8 9 /** 10 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 11 * system UI to enter an unobtrusive "low profile" mode. 12 * 13 * <p>This is for use in games, book readers, video players, or any other 14 * "immersive" application where the usual system chrome is deemed too distracting. 15 * 16 * <p>In low profile mode, the status bar and/or navigation icons may dim. 17 * 18 * @see #setSystemUiVisibility(int) 19 */ 20 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 21 22 /** 23 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 24 * system navigation be temporarily hidden. 25 * 26 * <p>This is an even less obtrusive state than that called for by 27 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 28 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 29 * those to disappear. This is useful (in conjunction with the 30 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 31 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 32 * window flags) for displaying content using every last pixel on the display. 33 * 34 * <p>There is a limitation: because navigation controls are so important, the least user 35 * interaction will cause them to reappear immediately. When this happens, both 36 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 37 * so that both elements reappear at the same time. 38 * 39 * @see #setSystemUiVisibility(int) 40 */ 41 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 42 43 /** 44 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 45 * into the normal fullscreen mode so that its content can take over the screen 46 * while still allowing the user to interact with the application. 47 * 48 * <p>This has the same visual effect as 49 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 50 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 51 * meaning that non-critical screen decorations (such as the status bar) will be 52 * hidden while the user is in the View's window, focusing the experience on 53 * that content. Unlike the window flag, if you are using ActionBar in 54 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 55 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 56 * hide the action bar. 57 * 58 * <p>This approach to going fullscreen is best used over the window flag when 59 * it is a transient state -- that is, the application does this at certain 60 * points in its user interaction where it wants to allow the user to focus 61 * on content, but not as a continuous state. For situations where the application 62 * would like to simply stay full screen the entire time (such as a game that 63 * wants to take over the screen), the 64 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 65 * is usually a better approach. The state set here will be removed by the system 66 * in various situations (such as the user moving to another application) like 67 * the other system UI states. 68 * 69 * <p>When using this flag, the application should provide some easy facility 70 * for the user to go out of it. A common example would be in an e-book 71 * reader, where tapping on the screen brings back whatever screen and UI 72 * decorations that had been hidden while the user was immersed in reading 73 * the book. 74 * 75 * @see #setSystemUiVisibility(int) 76 */ 77 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 78 79 /** 80 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 81 * flags, we would like a stable view of the content insets given to 82 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 83 * will always represent the worst case that the application can expect 84 * as a continuous state. In the stock Android UI this is the space for 85 * the system bar, nav bar, and status bar, but not more transient elements 86 * such as an input method. 87 * 88 * The stable layout your UI sees is based on the system UI modes you can 89 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 90 * then you will get a stable layout for changes of the 91 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 92 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 93 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 94 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 95 * with a stable layout. (Note that you should avoid using 96 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 97 * 98 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 99 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 100 * then a hidden status bar will be considered a "stable" state for purposes 101 * here. This allows your UI to continually hide the status bar, while still 102 * using the system UI flags to hide the action bar while still retaining 103 * a stable layout. Note that changing the window fullscreen flag will never 104 * provide a stable layout for a clean transition. 105 * 106 * <p>If you are using ActionBar in 107 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 108 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 109 * insets it adds to those given to the application. 110 */ 111 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 112 113 /** 114 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 115 * to be layed out as if it has requested 116 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 117 * allows it to avoid artifacts when switching in and out of that mode, at 118 * the expense that some of its user interface may be covered by screen 119 * decorations when they are shown. You can perform layout of your inner 120 * UI elements to account for the navigation system UI through the 121 * {@link #fitSystemWindows(Rect)} method. 122 */ 123 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 124 125 /** 126 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 127 * to be layed out as if it has requested 128 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 129 * allows it to avoid artifacts when switching in and out of that mode, at 130 * the expense that some of its user interface may be covered by screen 131 * decorations when they are shown. You can perform layout of your inner 132 * UI elements to account for non-fullscreen system UI through the 133 * {@link #fitSystemWindows(Rect)} method. 134 */ 135 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 136 137 /** 138 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 139 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 140 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 141 * user interaction. 142 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 143 * has an effect when used in combination with that flag.</p> 144 */ 145 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 146 147 /** 148 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 149 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 150 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 151 * experience while also hiding the system bars. If this flag is not set, 152 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 153 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 154 * if the user swipes from the top of the screen. 155 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 156 * system gestures, such as swiping from the top of the screen. These transient system bars 157 * will overlay app’s content, may have some degree of transparency, and will automatically 158 * hide after a short timeout. 159 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 160 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 161 * with one or both of those flags.</p> 162 */ 163 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 164 165 /** 166 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 167 */ 168 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 169 170 /** 171 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 172 */ 173 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 174 175 /** 176 * @hide 177 * 178 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 179 * out of the public fields to keep the undefined bits out of the developer's way. 180 * 181 * Flag to make the status bar not expandable. Unless you also 182 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 183 */ 184 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 185 186 /** 187 * @hide 188 * 189 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 190 * out of the public fields to keep the undefined bits out of the developer's way. 191 * 192 * Flag to hide notification icons and scrolling ticker text. 193 */ 194 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 195 196 /** 197 * @hide 198 * 199 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 200 * out of the public fields to keep the undefined bits out of the developer's way. 201 * 202 * Flag to disable incoming notification alerts. This will not block 203 * icons, but it will block sound, vibrating and other visual or aural notifications. 204 */ 205 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 206 207 /** 208 * @hide 209 * 210 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 211 * out of the public fields to keep the undefined bits out of the developer's way. 212 * 213 * Flag to hide only the scrolling ticker. Note that 214 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 215 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 216 */ 217 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 218 219 /** 220 * @hide 221 * 222 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 223 * out of the public fields to keep the undefined bits out of the developer's way. 224 * 225 * Flag to hide the center system info area. 226 */ 227 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 228 229 /** 230 * @hide 231 * 232 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 233 * out of the public fields to keep the undefined bits out of the developer's way. 234 * 235 * Flag to hide only the home button. Don't use this 236 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 237 */ 238 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 239 240 /** 241 * @hide 242 * 243 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 244 * out of the public fields to keep the undefined bits out of the developer's way. 245 * 246 * Flag to hide only the back button. Don't use this 247 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 248 */ 249 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 250 251 /** 252 * @hide 253 * 254 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 255 * out of the public fields to keep the undefined bits out of the developer's way. 256 * 257 * Flag to hide only the clock. You might use this if your activity has 258 * its own clock making the status bar's clock redundant. 259 */ 260 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 261 262 /** 263 * @hide 264 * 265 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 266 * out of the public fields to keep the undefined bits out of the developer's way. 267 * 268 * Flag to hide only the recent apps button. Don't use this 269 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 270 */ 271 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 272 273 /** 274 * @hide 275 * 276 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 277 * out of the public fields to keep the undefined bits out of the developer's way. 278 * 279 * Flag to disable the global search gesture. Don't use this 280 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 281 */ 282 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 283 284 /** 285 * @hide 286 * 287 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 288 * out of the public fields to keep the undefined bits out of the developer's way. 289 * 290 * Flag to specify that the status bar is displayed in transient mode. 291 */ 292 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 293 294 /** 295 * @hide 296 * 297 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 298 * out of the public fields to keep the undefined bits out of the developer's way. 299 * 300 * Flag to specify that the navigation bar is displayed in transient mode. 301 */ 302 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 303 304 /** 305 * @hide 306 * 307 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 308 * out of the public fields to keep the undefined bits out of the developer's way. 309 * 310 * Flag to specify that the hidden status bar would like to be shown. 311 */ 312 public static final int STATUS_BAR_UNHIDE = 0x10000000; 313 314 /** 315 * @hide 316 * 317 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 318 * out of the public fields to keep the undefined bits out of the developer's way. 319 * 320 * Flag to specify that the hidden navigation bar would like to be shown. 321 */ 322 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 323 324 /** 325 * @hide 326 * 327 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 328 * out of the public fields to keep the undefined bits out of the developer's way. 329 * 330 * Flag to specify that the status bar is displayed in translucent mode. 331 */ 332 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 333 334 /** 335 * @hide 336 * 337 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 338 * out of the public fields to keep the undefined bits out of the developer's way. 339 * 340 * Flag to specify that the navigation bar is displayed in translucent mode. 341 */ 342 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 343 344 /** 345 * @hide 346 */ 347 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
关于几个常用的我挨个试验了一下
getWindow().getDecorView().setSystemUiVisibility(标识)
然后操作了一下程序,得到下面的初步结论:
SYSTEM_UI_FLAG_FULLSCREEN | bar存在,内容消失 显示一个点 |
SYSTEM_UI_FLAG_HIDE_NAVIGATION | navigation_bar消失 |
SYSTEM_UI_FLAG_FULLSCREEN | status_bar消失 |
SYSTEM_UI_FLAG_LAYOUT_STABLE | 不变 |
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | 上下bar还在,但显示的内容拓展到被bar盖住的区域了好像 |
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | 上下bar还在,显示的内容拓展到上面bar的位置 |
SYSTEM_UI_FLAG_IMMERSIVE | 不变 |
SYSTEM_UI_FLAG_IMMERSIVE_STICKY | 不变 |
可以结合着源码里的官方注释来看看
一个新问题
看完这,我突然想起来之前遇到的另一个问题:
我写了一个popupwindow,希望它在靠上的位置弹出来时这么显示
结果它是这么显示的:
哎我去,当时我真是百思不得其解,因为各种高度我都考虑到,写到计算代码里,意思是一旦遇到顶部显示的情况,popupwindow就自动向下偏移一个距离完整显示。
另外,popupwindow作为一个弹出时单独在最上层显示的控件,就算我不控制它,它也不应该显示一半吧。
后来我实在没办法就强行在代码里增加了35左右的高度好让它完整显示。
现在看来,原来是界面显示的时候,顶部边界并不是状态栏的bottom,而是整个屏幕的顶部。出现这个情况是因为statusbar盖住了上面的一部分而已,只是我不知道罢了。。
好了,下次设计界面的时候我会注意把statusbar的高度减掉的。。。
以上就是我对Android状态栏的一点新理解。若不正确,但求拍砖。
参考: