[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;
标识位源码,5.0的SDK内容比原来的多了不少

关于几个常用的我挨个试验了一下

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状态栏的一点新理解。若不正确,但求拍砖。

参考:

动态显示和隐藏状态栏

原文地址:https://www.cnblogs.com/rossoneri/p/4316343.html