赞
踩
这章讲讲常用的系统UI管理,包括StatusBar,NavigationBar。
在看到这块时,感觉很常用,就记下来了。主要就是系统操作栏的隐藏、显示等操作。做工精细的app会对这些有要求。
相关名词:
StatusBar,状态栏,即顶部的一小块显示网络,电量,应用通知图标等的区域。
NavigationBar,导航栏,即底部的有返回,home等操作按钮的区域,有的没有。像华为荣耀7,底部就是返回,主页,以及最近应用列表菜单几个按钮。
Android4.0以上该效果不会使内容区域调整大小,但会使系统栏有消失的渐变效果,具体怎么消失因系统而异。
隐藏:
- View decorView = getActivity().getWindow().getDecorView();
- int uiOptions = View.SYSTEM_UI_FLAG_LOW_PROFILE;
- decorView.setSystemUiVisibility(uiOptions);
显示:
- View decorView = getActivity().getWindow().getDecorView();
- // 参数为0,清除所有flag
- decorView.setSystemUiVisibility(0);
在实验的时候,发现,魅族是顶部菜单栏有部分的内容消失,且其他的变暗(没有导航栏)。而荣耀7则只是导航栏按钮消失,但是导航栏的整体区域不消失,而状态栏没有变化。
这里指的是隐藏,而不是变暗,状态栏隐藏,会使内容区域重新调整大小。注意,官方建议,状态栏隐藏了,最好不要保留ActionBar。
- <application
- ...
- android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
- ...
- </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>,例如:
- <style name="AppTheme_FullScreen" parent="Theme.AppCompat.Light.NoActionBar">
- <!-- Customize your theme here. -->
- <item name="colorPrimary">@color/colorPrimary</item>
- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
- <item name="colorAccent">@color/colorAccent</item>
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowFullscreen">true</item>
- </style>
a)4.0及更低版本方法,通过设置WindowManager:
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // 如果Android版本低于16
- if (Build.VERSION.SDK_INT < 16) {
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- }
- setContentView(R.layout.activity_main);
- }
b)4.1及以上版本:
- View decorView = getWindow().getDecorView();
- // 隐藏状态栏
- int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
- decorView.setSystemUiVisibility(uiOptions);
- // 如果状态栏隐藏了,记住也要隐藏ActionBar(当然,此时你有ActionBar的情况),否则,空出状态栏一块太丑。
- ActionBar actionBar = getActionBar();
- if (actionBar != null) {
- actionBar.hide();
- }
a)当UIFlag被清除时,要重新去隐藏;
b)假如在onCreate()中隐藏状态栏,当用户切换页面状态栏会重新显示,返回该页面时,如果Activity没被回收就不会调用onCreate()方法,状态栏就不会隐藏。因此想一直保持没有状态栏,则需要在onResume()中或onWindowFocusChanged()中调用;
c)setSystemUiVisibility()方法只有当调用它的View是可见的时候才有效;
d)Navigation离开会使setSystemUIVisibility设置的Flag消失,隐藏的状态栏会重新出现。
使用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无效,去掉就可以了。
- View decorView = getWindow().getDecorView();
- // 隐藏导航栏与状态栏
- // SYSTEM_UI_FLAG_FULLSCREEN 4.1以上可获得,当然,保持应用在所有系统一致
- int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN;
- decorView.setSystemUiVisibility(uiOptions);
这个也有些注意点,但是与上面的状态栏的一致,不再重复。
这个与上面的状态栏一致,通过设置SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION标志。问题与解决也是一致的。
4.4以后引入SYSTEM_UI_FLAG_IMMERSIVE标志。通过setSystemUiVisibility()使app达到全屏效果。当与SYSTEM_UI_FLAG_HIDE_NAVIGATION与SYSTEM_UI_FLAG_FULLSCREEN结合使用,会隐藏状态栏与导航栏,并可以捕获屏幕触摸事件。
当使用沉浸式模式时,当用户从顶部向下或从底部向上滑动,都会使系统栏重新显示,这个效果我在开卷有益app中看到过,效果不错。同时会触发View.OnSystemUiVisibilityChangeListener()监听器。
a)隐藏
- private void hideSystemUI() {
- // 设置IMMERSIVE标记,设置内容出现在系统栏底部,则当系统栏隐藏消失时不会重新调整。
- mDecorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
- | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
- | View.SYSTEM_UI_FLAG_IMMERSIVE);
- }
b)显示,删除所有标志,仍然隐藏在系统栏下面
- private void showSystemUI() {
- mDecorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- }
如果只是想让系统栏只显示一会儿就再次隐藏,可以设置SYSTEM_UI_FLAG_IMMERSIVE_STICKY标志,且此标志不会触发触摸监听器,因为只是临时的状态。
如果想使用全屏模式实现暂时全屏模式(获得焦点,要隐藏系统栏,失去焦点,如dialog或popwindow则显示),则要在onWindowFocusChanged()中使用Handler.postDelayed()隔几秒之后再次隐藏。
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- if (hasFocus) {
- decorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- }
- }
在onCreate中添加监听器,可以让自己的UI保持与系统栏隐藏消失同步:
- View decorView = getWindow().getDecorView();
- decorView.setOnSystemUiVisibilityChangeListener
- (new View.OnSystemUiVisibilityChangeListener() {
- @Override
- public void onSystemUiVisibilityChange(int visibility) {
- // 注意系统栏将为“visible”,如果LOW_PROFILE, HIDE_NAVIGATION, 或 FULLSCREEN 标记没有一个被设置
- if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
- // 系统栏可见
- } else {
- // 系统栏不可见
- }
- }
- });
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上的实现方式。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。