SystemUI手势操作隐藏显示导航栏

在Android 12中,通过SystemUI手势操作来隐藏和显示导航栏主要涉及对系统UI的定制和编程控制。以下是一些实现这一功能的方法:

默认是隐藏

向上滑动

第一类. 使用WindowInsetsController

Android 12引入了一个新的WindowInsetsController类,它允许开发者更好地控制系统窗口的行为,包括导航栏的显示和隐藏。

1.1.步骤概述

  • AndroidManifest.xml文件中设置应用支持的最低SDK版本为Android 12(android:minSdkVersion="S")。
  • 在活动的onCreate方法中获取WindowInsetsController实例。
  • 使用hideshow方法来控制导航栏的显示和隐藏。

示例代码

复制代码
import androidx.appcompat.app.AppCompatActivity;  
import android.os.Bundle;  
import androidx.core.view.WindowInsetsCompat;  
import androidx.core.view.WindowInsetsControllerCompat;  
  
public class MainActivity extends AppCompatActivity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
  
        WindowInsetsControllerCompat controller = WindowInsetsControllerCompat(getWindow(), getWindow().getDecorView());  
  
        // 隐藏导航栏  
        controller.hide(WindowInsetsCompat.Type.navigationBars());  
  
        // 在需要时显示导航栏  
        // controller.show(WindowInsetsCompat.Type.navigationBars());  
  
        // 检查导航栏是否可见  
        boolean isVisible = controller.isVisible(WindowInsetsCompat.Type.navigationBars());  
    }  
}

第二类、修改系统源码

1.可以通过修改系统源码实现底部导航栏 的控制涉及的类

复制代码
Android10
frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java


android12
frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController

2.DisplayPolicy源码分析

复制代码
Android10源代码  
mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler,
                new SystemGesturesPointerEventListener.Callbacks() {
                    @Override
                    public void onSwipeFromTop() {
                        synchronized (mLock) {
                            if (mStatusBar != null) {
                                requestTransientBars(mStatusBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
                        }
                    }

                    @Override
                    public void onSwipeFromBottom() {
                        synchronized (mLock) {
                            if (mNavigationBar != null
                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
                        }
                    }

                    @Override
                    public void onSwipeFromRight() {
                        final Region excludedRegion = Region.obtain();
                        synchronized (mLock) {
                            mDisplayContent.calculateSystemGestureExclusion(
                                    excludedRegion, null /* outUnrestricted */);
                            final boolean excluded =
                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
                        }
                        excludedRegion.recycle();
                    }

                    @Override
                    public void onSwipeFromLeft() {
                        final Region excludedRegion = Region.obtain();
                        synchronized (mLock) {
                            mDisplayContent.calculateSystemGestureExclusion(
                                    excludedRegion, null /* outUnrestricted */);
                            final boolean excluded =
                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
                        }
                        excludedRegion.recycle();
                    }

                    @Override
                    public void onFling(int duration) {
                        if (mService.mPowerManagerInternal != null) {
                            mService.mPowerManagerInternal.setPowerBoost(
                                    Boost.INTERACTION, duration);
                        }
                    }

                    @Override
                    public void onDebug() {
                        // no-op
                    }

                    private WindowOrientationListener getOrientationListener() {
                        final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
                        return rotation != null ? rotation.getOrientationListener() : null;
                    }

                    @Override
                    public void onDown() {
                        final WindowOrientationListener listener = getOrientationListener();
                        if (listener != null) {
                            listener.onTouchStart();
                        }
                    }

                    @Override
                    public void onUpOrCancel() {
                        final WindowOrientationListener listener = getOrientationListener();
                        if (listener != null) {
                            listener.onTouchEnd();
                        }
                    }

                    @Override
                    public void onMouseHoverAtTop() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
                    }

                    @Override
                    public void onMouseHoverAtBottom() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
                    }

                    @Override
                    public void onMouseLeaveFromEdge() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                    }
                });




Android12源代码


 mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler,
                new SystemGesturesPointerEventListener.Callbacks() {
                    @Override
                    public void onSwipeFromTop() {
                        synchronized (mLock) {
                            if (mStatusBar != null) {
                                requestTransientBars(mStatusBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
                        }
                    }

                    @Override
                    public void onSwipeFromBottom() {
                        synchronized (mLock) {
                            if (mNavigationBar != null
                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
								
                                requestTransientBars(mNavigationBar);
                            }
							
							// 新增
							mContext.sendBroadcast(new Intent("com.android.action.swipefrombottom")); //自定义上滑广播
						 
                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
                        }
                    }

                    @Override
                    public void onSwipeFromRight() {
                        final Region excludedRegion = Region.obtain();
                        synchronized (mLock) {
                            mDisplayContent.calculateSystemGestureExclusion(
                                    excludedRegion, null /* outUnrestricted */);
                            final boolean excluded =
                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
                        }
                        excludedRegion.recycle();
                    }

                    @Override
                    public void onSwipeFromLeft() {
                        final Region excludedRegion = Region.obtain();
                        synchronized (mLock) {
                            mDisplayContent.calculateSystemGestureExclusion(
                                    excludedRegion, null /* outUnrestricted */);
                            final boolean excluded =
                                    mSystemGestures.currentGestureStartedInRegion(excludedRegion);
                            if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
                                    || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
                                requestTransientBars(mNavigationBar);
                            }
                            checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
                        }
                        excludedRegion.recycle();
                    }

                    @Override
                    public void onFling(int duration) {
                        if (mService.mPowerManagerInternal != null) {
                            mService.mPowerManagerInternal.setPowerBoost(
                                    Boost.INTERACTION, duration);
                        }
                    }

                    @Override
                    public void onDebug() {
                        // no-op
                    }

                    private WindowOrientationListener getOrientationListener() {
                        final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
                        return rotation != null ? rotation.getOrientationListener() : null;
                    }

                    @Override
                    public void onDown() {
                        final WindowOrientationListener listener = getOrientationListener();
                        if (listener != null) {
                            listener.onTouchStart();
                        }
                    }

                    @Override
                    public void onUpOrCancel() {
                        final WindowOrientationListener listener = getOrientationListener();
                        if (listener != null) {
                            listener.onTouchEnd();
                        }
                    }

                    @Override
                    public void onMouseHoverAtTop() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
                    }

                    @Override
                    public void onMouseHoverAtBottom() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                        Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
                        msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
                        mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
                    }

                    @Override
                    public void onMouseLeaveFromEdge() {
                        mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
                    }
                });

由于我们需要实现的是手势上滑隐藏导航栏,故只需关注onSwipeFromBottom方法,在其中触发事件时发送对应事件,然后载在SystemUI中接收对应事件实现隐藏显示效果。我直接在onSwipeFromBottom发送广播。

复制代码
            @Override
                    public void onSwipeFromBottom() {
                        synchronized (mLock) {
                            if (mNavigationBar != null
                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
								
                                requestTransientBars(mNavigationBar);
                            }
							
							// 新增
							mContext.sendBroadcast(new Intent("com.android.action.swipefrombottom")); //自定义上滑广播
						 
                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
                        }
                    }

3.实现如下

在向上滑动onSwipeFromBottom方法中发送广播,来通知navigarbar显示隐藏。

mContext.sendBroadcast(new Intent("com.android.action.swipefrombottom")); //自定义上滑广播

复制代码
类路径:frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java



                    @Override
                    public void onSwipeFromBottom() {
                        synchronized (mLock) {
                            if (mNavigationBar != null
                                    && mNavigationBarPosition == NAV_BAR_BOTTOM) {
								
                                requestTransientBars(mNavigationBar);
                            }
							
							// 新增
							mContext.sendBroadcast(new Intent("com.android.action.swipefrombottom")); //自定义上滑广播
						 
                            checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
                        }
                    }

3 StatusBar监听自定义广播然后实现导航栏显示和隐藏功能

代码内容

复制代码
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

 第一步 修改变量
 +代表新增的意思

+    private boolean navigationBarState = false;
+    private RegisterStatusBarResult result = null;

  // 注释局部变量改成全局变量
  // RegisterStatusBarResult result = null;

第二步 注释NavigationBar

  //createNavigationBar(result); //注释


第三步 注册广播 internalFilter.addAction全局搜索
   IntentFilter internalFilter = new IntentFilter();
         internalFilter.addAction(BANNER_ACTION_CANCEL);
         internalFilter.addAction(BANNER_ACTION_SETUP);
+        internalFilter.addAction("com.android.action.swipefrombottom");
         //internalFilter.addAction("com.android.action.swipefromtop");
         mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
                 null);



第四步 接收广播mBannerActionBroadcastReceiver系统自动

    private final BroadcastReceiver mBannerActionBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
                NotificationManager noMan = (NotificationManager)
                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
                noMan.cancel(com.android.internal.messages.nano.SystemMessageProto.SystemMessage.
                        NOTE_HIDDEN_NOTIFICATIONS);

                Settings.Secure.putInt(mContext.getContentResolver(),
                        Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
                if (BANNER_ACTION_SETUP.equals(action)) {
                    mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
                            true /* force */);
                    mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

                    );
                }
            }


            // 新增代码
			// 分割线
			else if("com.android.action.swipefrombottom".equals(action)){
	            //上滑事件
			     Log.d("StatusBar","swipefrombottom---666--");
			  if(!navigationBarState){
			        navigationBarState = true;
			        //加载导航栏
			        createNavigationBar(result);
			        mHandler.postDelayed(new Runnable() {
			                @Override
			                public void run() {
							  navigationBarState = false;
							// 移除导航栏
		                      mNavigationBarController.removeNavigationBar(mDisplayId);
			                }
			            },6000);
			  }
		    }else if("com.android.action.swipefromtop".equals(action)){
			     Log.d("StatusBar","swipefromtop--666-");
			//下滑事件
			   mNavigationBarController.removeNavigationBar(mDisplayId);
		   }
            // 新增代码
			// 分割线


        }
    };

在 StatusBar的makeStatusBarView中去掉加载导航栏的方法createNavigationBar(result)而在start()方法中监听系统手势上滑的自定义广播,然后在收到自定义广播后,弹出系统导航栏,三秒钟后消失导航栏

4.修改隐藏导航栏方法

复制代码
Android10 路径
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java

Android12 路径
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController

public class NavigationBarController implements Callbacks {
     
     
    //隐藏导航栏方法变为public 方便调用
-   void removeNavigationBar(int displayId) {

   // 变成公布方法
+  public void removeNavigationBar(int displayId) {
        NavigationBar navBar = mNavigationBars.get(displayId);
        if (navBar != null) {
            navBar.setAutoHideController(/* autoHideController */ null);
            navBar.destroyView();
            mNavigationBars.remove(displayId);
        }
    }
相关推荐
2501_940094021 小时前
emu系列模拟器最新汉化版 安卓版 怀旧游戏模拟器全集附可运行游戏ROM
android·游戏·安卓·模拟器
下位子1 小时前
『OpenGL学习滤镜相机』- Day9: CameraX 基础集成
android·opengl
参宿四南河三3 小时前
Android Compose SideEffect(副作用)实例加倍详解
android·app
火柴就是我4 小时前
mmkv的 mmap 的理解
android
没有了遇见4 小时前
Android之直播宽高比和相机宽高比不支持后动态获取所支持的宽高比
android
shenshizhong4 小时前
揭开 kotlin 中协程的神秘面纱
android·kotlin
vivo高启强5 小时前
如何简单 hack agp 执行过程中的某个类
android
沐怡旸5 小时前
【底层机制】 Android ION内存分配器深度解析
android·面试
你听得到115 小时前
肝了半个月,我用 Flutter 写了个功能强大的图片编辑器,告别image_cropper
android·前端·flutter
KevinWang_5 小时前
Android 原生 app 和 WebView 如何交互?
android