显示、隐藏NavigationBar(虚拟按键)

本文详细解析了如何在手机应用中通过广播监听实现导航栏的显示与隐藏功能,包括添加导航栏的视图、设置LayoutParams类型以及位置布局,以及在客户端通过开关控制广播触发显示与隐藏动作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在启动的时候,在 PhoneStatusBar的 start()方法中,注册了广播监听,用来显示、隐藏NavigationBar.
  1.     IntentFilter intentfilter=new IntentFilter();
  2.     intentfilter.addAction(ACTION_DISPLAY_NAV_BAR);
  3.     intentfilter.addAction(ACTION_HIDE_NAV_BAR);
  4.     mContext.registerReceiver(mNavBarStatuReceiver,intentfilter);

对相应的广播做处理。比如addNavbar()、removeView等操作。
private BroadcastReceiver mNavBarStatuReceiver=new BroadcastReceiver(){
        public void onReceive(Context context, Intent intent) {
            if (intent != null && intent.getAction() != null) {
                mNavBarStatuAction = intent.getAction();
                mHandler.removeCallbacks(showNavBarRunnable);
                mHandler.postDelayed(showNavBarRunnable, 300);
            }
        }
    };
    private Runnable showNavBarRunnable = new Runnable() {
        public void run() {
            synchronized (mQueueLock2) {
                if (ACTION_DISPLAY_NAV_BAR.equals(mNavBarStatuAction)) {
                    try {
                        if (mNavigationBarView == null) {
                            addNavBar();
                        }
                        if (mNavigationBarView != null) {
                            checkBarMode(MODE_TRANSPARENT,
                                    mNavigationBarWindowState, mNavigationBarView.getBarTransitions(), false);
                        }
                    } catch (Exception e) {    }
                if (ACTION_HIDE_NAV_BAR.equals(mNavBarStatuAction)) {
                    if (mNavigationBarView != null) {
                        mWindowManager.removeView(mNavigationBarView);
                    }
                    try {
                        mWindowManagerService.setHasNavigationBar(false);
                    } catch (RemoteException ex) {  }
                    mNavigationBarView = null;
                }
            }
        }
    };

现在对addNavBar做简单分析:
看代码就明白了,其实很简单。只是new一个view添加到 WindowManager 中去。仅此而已。

    private void addNavBar() {
    if (mNavigationBarView == null) {
        mNavigationBarView = (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar, null);
        mNavigationBarView.setDisabledFlags(mDisabled1);
        mNavigationBarView.setBar(this);
        prepareNavigationBarView();
    }
         mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
    }
最主要是这段代码并没有说把NavigationBar添加到屏幕的下方。继续看getNavigationBarLayoutParams()方法
    private WindowManager.LayoutParams getNavigationBarLayoutParams() {
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,  0
                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                PixelFormat.TRANSLUCENT);
        // this will allow the navbar to run in an overlay on devices that support this
        if (ActivityManager.isHighEndGfx()) {
            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }

        lp.setTitle("NavigationBar");
        lp.windowAnimations = 0;
        return lp;
    }
这里设置了LayoutParams,其中主要是设置了Type:WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,这是在WindowManager的LayoutParams中定义的值。
绘制界面的时候在 PhoneWindowManager中的 layoutWindowLw方法中进行判断Type:
在这里进行了具体的位置设置,大概意思是把 TYPE_NAVIGATION_BAR_PANEL类型的位置参数设置在屏幕底部。

那么问题来了。是在哪里发的ACTION_DISPLAY_NAV_BAR和ACTION_HIDE_NAV_BAR广播呢?是openGrok上搜索发现,这两个广播在原生系统AOSP里面是没有的,而是三方加的。
在我们的项目中,是客户自己添加的。如下:
BqDisplaySettings.java中添加了一个选项开关,用来控制是否显示虚拟按键,打开或者关闭开关发送相应的广播,然后PhoneStatusBar.java接受广播并处理广播。
到这里NavigationBar的显示和隐藏功能大概讲解完了。

<think>我们正在讨论在Android11中隐藏导航栏(NavigationBar)的问题。根据提供的引用,我们可以找到几种方法。在Android中,导航栏通常指的是屏幕底部的虚拟按键(如返回键、主页键、最近任务键)。隐藏导航栏可以让应用进入沉浸式模式,提供更大的屏幕空间。根据引用[3],我们可以使用`setSystemUiVisibility`方法来隐藏导航栏和状态栏。但是需要注意的是,在Android11(API级别30)中,`setSystemUiVisibility`方法已经被废弃,推荐使用`WindowInsetsController`。因此,在Android11及更高版本中,我们应该使用新的API来实现隐藏导航栏。下面我将提供两种方法:1.使用新的`WindowInsetsController`API(推荐,适用于Android11及更高版本)2.使用旧的`setSystemUiVisibility`方法(兼容较低版本,但注意在Android11中已废弃)方法一(推荐):在Activity中,我们可以通过获取窗口的`WindowInsetsController`来控制系统栏的显示隐藏导航栏的代码:```javaif(Build.VERSION.SDK_INT>=Build.VERSION_CODES.R){//Android11(API30)及更高版本ViewdecorView=getWindow().getDecorView();WindowInsetsControllercontroller=decorView.getWindowInsetsController();if(controller!=null){//隐藏导航栏controller.hide(WindowInsets.Type.navigationBars());//设置导航栏行为:当用户滑动屏幕边缘时暂时显示,然后自动隐藏controller.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);}}else{//旧版本Android(API30以下)ViewdecorView=getWindow().getDecorView();intuiOptions=View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;decorView.setSystemUiVisibility(uiOptions);}```方法二(兼容旧版本):对于旧版本,我们仍然可以使用`setSystemUiVisibility`,但需要注意在Android11中该方法已被废弃,所以我们可以通过条件判断来使用。上面的代码中已经包含了旧版本的实现。另外,根据引用[1]和[2]中的内容,我们还需要注意以下几点:-隐藏导航栏后,当用户与屏幕交互时(例如触摸屏幕),导航栏可能会重新出现。我们可以使用`IMMERSIVE_STICKY`标志来使导航栏在短暂出现后自动隐藏。-在隐藏导航栏的同时,我们可能也需要隐藏状态栏(即全屏模式),但这不是必须的,可以根据应用需求决定。此外,我们还需要考虑键盘的出现。在引用[1]中提到,当软键盘出现时,可能会影响沉浸式模式。因此,我们需要测试在输入时导航栏的行为。最后,我们可以在Activity的`onResume`方法中调用上述代码,以确保每次回到Activity时都保持隐藏导航栏。示例代码(在Activity的onResume中调用):```java@OverrideprotectedvoidonResume(){super.onResume();hideNavigationBar();}privatevoidhideNavigationBar(){//使用上面方法一中的代码}```注意:在Android11中,新的`WindowInsetsController`提供了更精细的控制,包括导航栏、状态栏和输入法(IME)等系统栏的显示隐藏。总结:在Android11中隐藏导航栏,推荐使用新的`WindowInsetsController`API,同时为了兼容旧版本,可以结合条件判断使用旧方法。§§相关问题§§1.如何在Android11中隐藏状态栏?2.如何让应用的内容显示在导航栏后面(即全屏显示,但导航栏覆盖在内容上)?3.在Android中,沉浸式模式和全屏模式有什么区别?4.如何监听导航栏的显示隐藏事件?</think>### Android 11 隐藏导航栏的实现方法 在 Android 11 (API 30)隐藏导航栏(Navigation Bar),推荐使用新的 `WindowInsetsController` API,替代已废弃的 `setSystemUiVisibility()` 方法。以下是完整实现步骤: #### 方法一:使用 WindowInsetsController(推荐) ```java // 在 Activity 的 onCreate 或 onResume 中调用 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { final WindowInsetsController controller = getWindow().getInsetsController(); if (controller != null) { // 隐藏导航栏 controller.hide(WindowInsets.Type.navigationBars()); // 设置隐藏行为:滑动屏幕边缘时临时显示 controller.setSystemBarsBehavior( WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE ); } } ``` #### 方法二:兼容旧版本(API < 30) ```java View decorView = getWindow().getDecorView(); int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; decorView.setSystemUiVisibility(uiOptions); ``` #### 关键注意事项: 1. **权限声明** 在 `AndroidManifest.xml` 中添加全屏权限: ```xml <activity android:name=".MainActivity" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> </activity> ``` 2. **行为模式** - `BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE`:滑动边缘时临时显示(推荐) - `BEHAVIOR_SHOW_BARS_BY_TOUCH`:触摸屏幕时显示 - `BEHAVIOR_DEFAULT`:系统默认行为 3. **恢复显示处理** 当导航栏临时显示后,系统会自动隐藏。如需手动控制: ```java // 重新隐藏导航栏 controller.hide(WindowInsets.Type.navigationBars()); ``` 4. **键盘交互** 软键盘弹出时可能显示导航栏,需在 `onConfigurationChanged()` 中重新调用隐藏方法[^1]。 > **实测效果**:导航栏将被完全隐藏,用户从屏幕底部上滑可临时呼出导航栏,松手后自动隐藏(沉浸式体验)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值