在Android 4.0及其以上的版本中,出现了一个很屌的东西,叫做Navigation Bar,它和Status Bar一上一下相互交映,影响了我们的全屏。
低级隐藏
这个东西其实是可以隐藏和显示的,下面是Google给出的方法,此方法必须在Android 4.0以上的系统中使用,当然4.0以下也没有(也就是API 14),直接把这段代码粘贴在你的Activity的onCreate()方法中就可以了:
1 2 3 4 5 6 7 8 |
View decorView = getWindow().getDecorView(); // Hide both the navigation bar and the status bar. // system_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as // a general rule, you should design your app to hide the status bar whenever you // hide the navigation bar. int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions); |
但是这么做是有缺陷的,Google共给出了5个注意事项,我只看懂以下几个:
a) 使用这种设置flag的方式虽然暂时隐藏了Navigation Bar,但是用户触摸屏幕的任何地方flags将会被清除,也就是说你的设置,在用户触摸屏幕后会失效;
b) 一但你设置的flags被清除后,如果你再想隐藏Navigation Bar,需要重新设置,这个需要监听一个事件,看文章最后;
c) 你设置UI flags的位置很重要,也就是上面的代码的放置位置,如果你放到onCreate()方法中的时候,如果用户通过Home键回到桌面,当你重新打开的时候,由于这是onCreate()方法不会再次被调用,所以Navigation Bar 不再隐藏。如果你想要你的设置在上面的情况有效你需要在 onResume() or onWindowFocusChanged()中设置UI flags;
d)The method setSystemUiVisibility() only has an effect if the view you call it from is visible.(哥实在是翻译不出来,也没看懂)我的翻译:只有你调用setSystemUiVisibility()这个方法的View是可见状态下的时候,这个方法才会起作用。我们都知道,其实Activity的显示是有一个View的,就是那个从window中调用的getDecorView()方法,每个Activity都有一个decorview对象,这个就是Activity的渲染机制了。
e) Navigating away from the view causes flags set with setSystemUiVisibility() to be cleared.(额,这句英语也是屌的不行)同样我的翻译:当导航离开这个View的时候会使得通过 setSystemUiVisibility()这个方法设置的flags被清除,也就是说所有的在这个view上设置的全屏和隐藏NavigationBar的flag都将失效。
高级解决方案
通过按钮事件控制Navigation Bar的显示和隐藏。看下面的代码来自Google的Example,只要在按钮中调用这个方法,就可以随意切换显示和隐藏Navigation Bar了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/** * Detects and toggles immersive mode (also known as "hidey bar" mode). */ public void toggleHideyBar() { // The UI options currently enabled are represented by a bitfield. // getSystemUiVisibility() gives us that bitfield. int uiOptions = getWindow().getDecorView().getSystemUiVisibility(); int newUiOptions = uiOptions; boolean isImmersiveModeEnabled = ((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions); if (isImmersiveModeEnabled) { Log.i(TAG, "Turning immersive mode mode off. "); } else { Log.i(TAG, "Turning immersive mode mode on."); } // Navigation bar hiding: Backwards compatible to ICS. if (Build.version.SDK_INT >= 14) { newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; } // Status bar hiding: Backwards compatible to Jellybean if (Build.VERSION.SDK_INT >= 16) { newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN; } // Immersive mode: Backward compatible to KitKat. // Note that this flag doesn't do anything by itself, it only augments the behavior // of HIDE_NAVIGATION and FLAG_FULLSCREEN. For the purposes of this sample // all three flags are being toggled together. // Note that there are two immersive mode UI flags, one of which is referred to as "sticky". // Sticky immersive mode differs in that it makes the navigation and status bars // semi-transparent, and the UI flag does not get cleared when the user interacts with // the screen. if (Build.VERSION.SDK_INT >= 18) { newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; } getWindow().getDecorView().setSystemUiVisibility(newUiOptions); } |
Navigation Bar 透明遮挡内容
Android 越出越牛X,当Android 4.1以后的版本,如果不是必须,不一定非要把他隐藏掉。因为你的内容View可以放到Navigation Bar 下面,所以这个时候当Navigation Bar显示或者隐藏的时候,不会引起你的内容View重新计算大小。你可以使用SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_LAYOUT_STABLE来实现。(个人目测这个用途不是太大吧)
Android 4.4 Immersive Mode“沉浸式全屏
这个比较好玩,Status Bar 和 Navigation Bar 是以透明的方式显示的,但是这个要在 API 19 之上使用。
沉浸式全屏是什么意思?就是支持沉浸式全屏的应用在Android 4.4的手机上会自动全屏显示,并不会出现恼人的虚拟键。而当我们需要虚拟键的时候,只要在屏幕底部轻轻滑动一下即可调出虚拟键,而且虚拟键是以透明的状态显示的。
Android 4.4 中提供了 SYSTEM_UI_FLAG_IMMERSIVE 和 SYSTEM_UI_FLAG_IMMERSIVE_STICKY 标记, 可以用这两个标记与 SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_FULLSCREEN 一起使用来实现沉浸模式。
当沉浸式全屏模式启用的时候,你的Activity会继续接受各类的触摸事件。用户可以通过在状态栏与导航栏原来区域的边缘向内滑动让系统栏重新显示。这个操作清空了SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_FULLSCREEN 两个标志,因此系统栏重新变得可见。这个操作同时也触发了View.OnSystemUiVisibilityChangeListener。如果你想让系统栏在一段时间后自动隐藏的话,你应该使用SYSTEM_UI_FLAG_IMMERSIVE_STICKY标签。请注意,STICKY标签不会触发任何的监听器,因为在这个模式下展示的系统栏是处于暂时的状态。
使用非STICKY的沉浸模式
当你使用SYSTEM_UI_FLAG_IMMERSIVE标签的时候,它是基于其他设置过的标签(SYSTEM_UI_FLAG_HIDE_NAVIGATION和SYSTEM_UI_FLAG_FULLSCREEN)来隐藏系统栏的。当用户向内滑动,系统栏重新显示并保持可见。用其他的UI标签(如SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION和SYSTEM_UI_FLAG_LAYOUT_STABLE)来防止系统栏隐藏时内容区域大小发生变化是一种很不错的方法。你也需要确保Action Bar和其他系统UI控件同时进行隐藏。下面这段代码展示了如何在不改变内容区域大小的情况下,隐藏与显示状态栏和导航栏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// This snippet hides the system bars. private void hideSystemUI() { // Set the IMMERSIVE flag. // Set the content to appear under the system bars so that the content // doesn't resize when the system bars hide and show. 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); } // This snippet shows the system bars. It does this by removing all the flags // except for the ones that make the content appear under the system bars. private void showSystemUI() { mDecorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } |
你可能同时也希望在如下的几种情况下使用IMMERSIVE
标签来提供更好的用户体验:
- 注册一个监听器来监听系统UI的变化。
- 实现
onWindowFocusChanged()
函数。如果窗口获取了焦点,你可能需要对系统栏进行隐藏。如果窗口失去了焦点,比如说弹出了一个对话框或菜单,你可能需要取消那些将要在Handler.postDelayed()
或其他地方的隐藏操作。 - 实现一个
GestureDetector
,它监听了onSingleTapUp(MotionEvent)
事件。可以使用户点击内容区域来切换系统栏的显示状态。单纯的点击监听可能不是最好的解决方案,因为当用户在屏幕上拖动手指的时候(假设点击的内容占据了整个屏幕),这个事件也会被触发。
使用STICKY的沉浸模式
当使用了SYSTEM_UI_FLAG_IMMERSIVE_STICKY标签的时候,向内滑动的操作会让系统栏临时显示,并处于半透明的状态。此时没有标签会被清除,系统UI可见性监听器也不会被触发。如果用户没有进行操作,系统栏会在一段时间内自动隐藏。下面是一段实现代码。一旦窗口获取了焦点,只要简单的设置IMMERSIVE_STICKY与上面讨论过的其他标签即可。
1 2 3 4 5 6 7 8 9 10 11 12 |
@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);} } |
注意,如果你想实现IMMERSIVE_STICKY的自动隐藏效果,同时也需要展示你自己的UI控件。你只需要使用IMMERSIVE与Handler.postDelayed()或其他类似的东西,让它几秒后重新进入沉浸模式即可。
监听事件的方式获取屏幕Navigation Bar的变化,然后做出不同的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
private static Handler sHandler; protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); sHandler = new Handler(); sHandler.post(mHideRunnable); // hide the navigation bar final View decorView = getWindow().getDecorView(); decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { sHandler.post(mHideRunnable); // hide the navigation bar } }); } Runnable mHideRunnable = new Runnable() { @Override public void run() { int flags; int curApiVersion = android.os.Build.VERSION.SDK_INT; // This work only for android 4.4+ if(curApiVersion >= Build.VERSION_CODES.KITKAT){ // This work only for android 4.4+ // hide navigation bar permanently in android activity // touch the screen, the navigation bar will not show flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_FULLSCREEN; }else{ // touch the screen, the navigation bar will show flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; } // must be executed in main thread :) getWindow().getDecorView().setSystemUiVisibility(flags); } }; |
原文链接:http://www.07net01.com/2015/04/822292.html
原文链接:http://blog.csdn.net/sdvch/article/details/44209959
转载请注明:无名小站 » Android 全屏方案(隐藏NavigationBar)