在Android 7.0隐藏导航栏和状态栏的一些方法

--- by Blue.Wu


背景:近期笔者在某款app时,需求要对导航栏(返回,home键,recent键的那部分)进行隐藏,此外还要做相关操作的屏蔽避免导航栏恢复显示。原本的方案是通过发广播给system ui,在system ui做remove导航栏的操作实现。后来架构设计阶段评估该方案对于外部模块的耦合太强,因此希望对方案进行优化,要求只在app自身做改动就可以实现。经过一番折腾完成之后,特将一些心得整理出来供参考。

 

心得1. 如何在不拉伸主要显示区域情况下,隐藏导航栏和状态栏。

笔者原本采用如下代码实现隐藏效果:

View decorView = activity.getWindow().getDecorView();

           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);

实践后发现虽然能实现隐藏状态栏和导航栏,但会出现原有显示区域的布局被拉伸的情况。这与我们的要求不相符,详细研究ViewsetSystemUiVisibility方法可以传入的flag的含义和用法如下:

   1. View.SYSTEM_UI_FLAG_VISIBLE:显示状态栏,Activity不全屏显示(恢复到有状态的正常情况)

   2. View.INVISIBLE:隐藏状态栏,同时Activity会伸展全屏显示。

   3. View.SYSTEM_UI_FLAG_FULLSCREENActivity全屏显示,且状态栏被隐藏覆盖掉。

   4. View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREENActivity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住。

   5. View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

   6. View.SYSTEM_UI_LAYOUT_FLAGS:效果同View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

   7. View.SYSTEM_UI_FLAG_HIDE_NAVIGATION:隐藏虚拟按键(导航栏)。有些手机会用虚拟按键来代替物理按键。

   8. View.SYSTEM_UI_FLAG_LOW_PROFILE:状态栏显示处于低能显示状态(low profile模式),状态栏上一些图标显示会被隐藏。

   9.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY:粘性沉浸模式,向内滑动的操作会让系统栏临时显示,并处于半透明的状态。此时没有标签会被清除,系统UI可见性监听器也不会被触发。如果用户没有进行操作,系统栏会在一段时间内自动隐藏。

   10.View.SYSTEM_UI_FLAG_IMMERSIVE:非粘性沉浸模式,它是基于其他设置过的标签(SYSTEM_UI_FLAG_HIDE_NAVIGATIONSYSTEM_UI_FLAG_FULLSCREEN)来隐藏系统栏的。当用户向内滑动,系统栏重新显示并保持可见。

 

通过上面的分析可以发现,带有LAYOUT的flag,表示Activity会延伸到原本属于状态栏或导航栏的位置,所以导致了布局拉伸;在要求隐藏状态栏的地方,只需要用View.SYSTEM_UI_FLAG_FULLSCREEN即可。这时候,导航栏存在,状态栏隐藏并且不会拉伸。

若要求导航栏和状态栏都隐藏,采用View.SYSTEM_UI_FLAG_FULLSCREEN和 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION配合即可。也可以使用View.SYSTEM_UI_FLAG_IMMERSIVE_STICKYView.SYSTEM_UI_FLAG_HIDE_NAVIGATION配合,效果是一样的。

 

心得2. 如何屏蔽触摸手势滑动调出导航栏。

上述的设置还是无法解决点击屏幕导航栏恢复的问题。经过查找资料了解到滑动屏幕主要会被PhoneWindowManagerSystemGesturesPointerEventListener所截获,而且研究发现,笔者当前采用的mtk方案framework有针对设置了FULL_SCREEN的界面无法禁止状态栏下拉的问题,做了一些扩展,包括在View类中增加了public static final int SYSTEM_UI_FLAG_IMMERSIVE_GESTURE_ISOLATED = 0x00002000并在SystemGesturesPointerEventListeneronSwipeFromTop,onSwipeFromBottom等方法里添加isGestureIsolated()方法判断,isGestureIsolated代码如下:

1.   private boolean isGestureIsolated() {  

2.  +                        WindowState win = mFocusedWindow != null ? mFocusedWindow : mTopFullscreenOpaqueWindowState;  

3.  +                        if (win != null && (win.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_IMMERSIVE_GESTURE_ISOLATED) != 0)  

4.  +                            return true;  

5.  +                        else  

6.  +                            return false;  

7.  +                    }  

因此我们只需要在setSystemUiVisibility中加上SYSTEM_UI_FLAG_IMMERSIVE_GESTURE_ISOLATED就可以屏蔽在屏幕上的滑动了。

注:该方法仅针对MTK手机平台适用,若是高通平台,则需要framework自行扩展类似接口。

 

心得3. 如何在对话框调起时不显示状态栏。

setSystemUiVisibility隐藏状态栏后,弹出Dialog或输入法键盘时,状态栏又会跑出来.

在请教了资深开发者之后发现原因,如下是frameworkDiaolgshow的处理:

public void show() {

                      ......

                     WindowManager.LayoutParams l = mWindow.getAttributes();
                      ......

                     mWindowManager.addView(mDecor, l);
                     ......

               }

          dialog是在窗体addview,并且沿用了原窗体的参数.

          因此如果原窗体没有设置full_screenflag,则addview刷新窗体时,也是非full_screen而把状态栏调出来.

        (输入法键盘的显示也是类似情况)

     

      解决方案:如果要隐藏状态栏并且避免dialog弹出时状态栏跑出来,需要改变Window的参数即可:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);


你可能感兴趣的:(在Android 7.0隐藏导航栏和状态栏的一些方法)