前段時間遇到幾個關於狀態欄的問題,又了解了一下狀態欄相關的知識,現在做一下記錄。
本文地址: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狀態欄的一點新理解。若不正確,但求拍磚。
參考:
