当前位置:   article > 正文

管理系统UI(StatusBar、NavigationBar)

管理系统ui

这章讲讲常用的系统UI管理,包括StatusBar,NavigationBar。

一、概览

在看到这块时,感觉很常用,就记下来了。主要就是系统操作栏的隐藏、显示等操作。做工精细的app会对这些有要求。

相关名词:

StatusBar,状态栏,即顶部的一小块显示网络,电量,应用通知图标等的区域。

NavigationBar,导航栏,即底部的有返回,home等操作按钮的区域,有的没有。像华为荣耀7,底部就是返回,主页,以及最近应用列表菜单几个按钮。

二、干货

1.使SystemBar变暗(注意不是隐藏)

Android4.0以上该效果不会使内容区域调整大小,但会使系统栏有消失的渐变效果,具体怎么消失因系统而异。

隐藏:

  1. View decorView = getActivity().getWindow().getDecorView();
  2. int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE;
  3. decorView.setSystemUiVisibility(uiOptions);
显示:

  1. View decorView = getActivity().getWindow().getDecorView();
  2. // 参数为0,清除所有flag
  3. decorView.setSystemUiVisibility(0);
在实验的时候,发现,魅族是顶部菜单栏有部分的内容消失,且其他的变暗(没有导航栏)。而荣耀7则只是导航栏按钮消失,但是导航栏的整体区域不消失,而状态栏没有变化。

2.隐藏不同Android版本的StatusBar

这里指的是隐藏,而不是变暗,状态栏隐藏,会使内容区域重新调整大小。注意,官方建议,状态栏隐藏了,最好不要保留ActionBar。

1)在manifest中指定主题为全屏的:

  1. <application
  2. ...
  3. android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
  4. ...
  5. </application>
优点是不需要代码,而且有平滑的UI变化。

但是,我们现在大部分都是继承AppCompatActivity来实现,而theme中不可以使用非AppCompat的theme,否则会抛出IllegalStateException:You need to use a Theme.AppCompat theme(or descendant) with this activty.即要使用AppCompat主题或其子主题。解决方法就是,在继承自AppCompat主题之一的theme中,添加<item name="android:windowFullScreen">true</item>,例如:

  1. <style name="AppTheme_FullScreen" parent="Theme.AppCompat.Light.NoActionBar">
  2. <!-- Customize your theme here. -->
  3. <item name="colorPrimary">@color/colorPrimary</item>
  4. <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
  5. <item name="colorAccent">@color/colorAccent</item>
  6. <item name="android:windowNoTitle">true</item>
  7. <item name="android:windowFullscreen">true</item>
  8. </style>

2)代码设置:

a)4.0及更低版本方法,通过设置WindowManager:

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. // 如果Android版本低于16
  5. if (Build.VERSION.SDK_INT < 16) {
  6. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  7. WindowManager.LayoutParams.FLAG_FULLSCREEN);
  8. }
  9. setContentView(R.layout.activity_main);
  10. }
b)4.1及以上版本:

  1. View decorView = getWindow().getDecorView();
  2. // 隐藏状态栏
  3. int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
  4. decorView.setSystemUiVisibility(uiOptions);
  5. // 如果状态栏隐藏了,记住也要隐藏ActionBar(当然,此时你有ActionBar的情况),否则,空出状态栏一块太丑。
  6. ActionBar actionBar = getActionBar();
  7. if (actionBar != null) {
  8. actionBar.hide();
  9. }

3)注意:

a)当UIFlag被清除时,要重新去隐藏;

b)假如在onCreate()中隐藏状态栏,当用户切换页面状态栏会重新显示,返回该页面时,如果Activity没被回收就不会调用onCreate()方法,状态栏就不会隐藏。因此想一直保持没有状态栏,则需要在onResume()中或onWindowFocusChanged()中调用;

c)setSystemUiVisibility()方法只有当调用它的View是可见的时候才有效;

d)Navigation离开会使setSystemUIVisibility设置的Flag消失,隐藏的状态栏会重新出现。

3)使activity内容显示在状态栏后面(4.1及以上):

使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN标记以及SYSTEM_UI_FLAG_LAYOUT_STABLE(后者用于维护稳定布局)。与上述的SYSTEM_UI_FLAG_FULLSCREEN区别在于,这个会将布局显示在StatusBar下面,且StatusBar仍然存在,但是有个问题要注意,就是状态栏会覆盖一部分页面的内容,用户体验当然不好,解决方案为,在顶部布局中,比如toolbar等中添加android:fitsSystemWindows为true,可以使父容器留出状态栏的位置。也可以通过重写fitSystemWindows(Rect insets)方法控制内容区相对于系统栏的布局方式。当内容区发生变化,图层会调用该方法,允许窗口调整内容区域,使内容区给状态栏留出空间。

在实践时遇到个问题,就是使用android:fitsSystemWindows时,发现,死活留不出状态栏位置,后来发现在theme中我设置了android:windowFullScreen属性,使上面的fits无效,去掉就可以了。

3.隐藏导航栏

1)代码设置,使用SYSTEM_UI_FLAG_HIDE_NAVIGATION标志

  1. View decorView = getWindow().getDecorView();
  2. // 隐藏导航栏与状态栏
  3. // SYSTEM_UI_FLAG_FULLSCREEN 4.1以上可获得,当然,保持应用在所有系统一致
  4. int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
  5. decorView.setSystemUiVisibility(uiOptions);

这个也有些注意点,但是与上面的状态栏的一致,不再重复。

2)使内容显示在导航栏后面(4.1及以上)

这个与上面的状态栏一致,通过设置SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION标志。问题与解决也是一致的。

4.沉浸式全屏模式

1)沉浸式全屏

4.4以后引入SYSTEM_UI_FLAG_IMMERSIVE标志。通过setSystemUiVisibility()使app达到全屏效果。当与SYSTEM_UI_FLAG_HIDE_NAVIGATION与SYSTEM_UI_FLAG_FULLSCREEN结合使用,会隐藏状态栏与导航栏,并可以捕获屏幕触摸事件。

当使用沉浸式模式时,当用户从顶部向下或从底部向上滑动,都会使系统栏重新显示,这个效果我在开卷有益app中看到过,效果不错。同时会触发View.OnSystemUiVisibilityChangeListener()监听器。

a)隐藏

  1. private void hideSystemUI() {
  2. // 设置IMMERSIVE标记,设置内容出现在系统栏底部,则当系统栏隐藏消失时不会重新调整。
  3. mDecorView.setSystemUiVisibility(
  4. View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  5. | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  6. | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  7. | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
  8. | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
  9. | View.SYSTEM_UI_FLAG_IMMERSIVE);
  10. }
b)显示,删除所有标志,仍然隐藏在系统栏下面

  1. private void showSystemUI() {
  2. mDecorView.setSystemUiVisibility(
  3. View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  4. | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  5. | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
  6. }

2)暂时沉浸式全屏

如果只是想让系统栏只显示一会儿就再次隐藏,可以设置SYSTEM_UI_FLAG_IMMERSIVE_STICKY标志,且此标志不会触发触摸监听器,因为只是临时的状态。

如果想使用全屏模式实现暂时全屏模式(获得焦点,要隐藏系统栏,失去焦点,如dialog或popwindow则显示),则要在onWindowFocusChanged()中使用Handler.postDelayed()隔几秒之后再次隐藏。

  1. @Override
  2. public void onWindowFocusChanged(boolean hasFocus) {
  3. super.onWindowFocusChanged(hasFocus);
  4. if (hasFocus) {
  5. decorView.setSystemUiVisibility(
  6. View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  7. | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  8. | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  9. | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
  10. | View.SYSTEM_UI_FLAG_FULLSCREEN
  11. | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
  12. }
  13. }

3)监听系统栏可见变化

在onCreate中添加监听器,可以让自己的UI保持与系统栏隐藏消失同步:

  1. View decorView = getWindow().getDecorView();
  2. decorView.setOnSystemUiVisibilityChangeListener
  3. (new View.OnSystemUiVisibilityChangeListener() {
  4. @Override
  5. public void onSystemUiVisibilityChange(int visibility) {
  6. // 注意系统栏将为“visible”,如果LOW_PROFILE, HIDE_NAVIGATION, 或 FULLSCREEN 标记没有一个被设置
  7. if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
  8. // 系统栏可见
  9. } else {
  10. // 系统栏不可见
  11. }
  12. }
  13. });

4)使用场景

a)需要频繁操作系统栏时,可以使用SYSTEM_UI_FLAG_IMMERSIVE沉浸式全屏模式,如阅读类以及新闻类app;

b)不需要频繁操作系统栏时,使用SYSTEM_UI_IMMERSIVER_STICKY暂时全屏模式,如游戏或绘图类app;

c)不需要操作系统栏时,可以不使用会显示状态栏的模式。直接隐藏即可。

三、总结

上述总共讲了三种系统栏的操作。

1)变暗操作,这个没有隐藏,只是把系统栏变暗,还是能看到的。各品牌机效果不一样。

2)隐藏系统栏操作,这里分两种情况:

a)使用SYSTEM_UI_FLAG_FULLSCREEN等标志,使系统栏隐藏,但是如果失去焦点,则会再次显示。当然,我们也可以再次隐藏。

b)使用SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN和SYSTEM_UI_FLAG_LAYOUT_STABLE标志隐藏,但是要注意状态栏遮住内容的问题,可以使用fitsSystemWindow属性等方法解决。

两者区别在于,上面的是系统栏与内容顺序的布局,而下面的是内容与系统栏重叠布局,且在系统栏后面。

3)沉浸式全屏模式。

正常我们开发应用,会选择显示StatusBar。针对不同版本适配,可以选择,在4.4以下的版本仍然有StatusBar,不设置全屏,4.4以上,选择内容在状态栏后面的全屏,同时,设置状态栏为透明的(getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSPARENT_STATUS, WindowManager.LayoutParams.FLAG_TRANPARENT_STATUS)这样就可以了),达到最佳效果。当然还有SystemBarTintManager.jar中提供的一些便捷方法,原理也是基于API上的实现方式。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/113445
推荐阅读
  

闽ICP备14008679号