在Android 12中,通过SystemUI手势操作来隐藏和显示导航栏主要涉及对系统UI的定制和编程控制。以下是一些实现这一功能的方法:
默认是隐藏
向上滑动
第一类. 使用WindowInsetsController
Android 12引入了一个新的WindowInsetsController
类,它允许开发者更好地控制系统窗口的行为,包括导航栏的显示和隐藏。
1.1.步骤概述:
- 在
AndroidManifest.xml
文件中设置应用支持的最低SDK版本为Android 12(android:minSdkVersion="S"
)。 - 在活动的
onCreate
方法中获取WindowInsetsController
实例。 - 使用
hide
和show
方法来控制导航栏的显示和隐藏。
示例代码:
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.javaandroid12
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() {@Overridepublic void onSwipeFromTop() {synchronized (mLock) {if (mStatusBar != null) {requestTransientBars(mStatusBar);}checkAltBarSwipeForTransientBars(ALT_BAR_TOP);}}@Overridepublic void onSwipeFromBottom() {synchronized (mLock) {if (mNavigationBar != null&& mNavigationBarPosition == NAV_BAR_BOTTOM) {requestTransientBars(mNavigationBar);}checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);}}@Overridepublic 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();}@Overridepublic 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();}@Overridepublic void onFling(int duration) {if (mService.mPowerManagerInternal != null) {mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, duration);}}@Overridepublic void onDebug() {// no-op}private WindowOrientationListener getOrientationListener() {final DisplayRotation rotation = mDisplayContent.getDisplayRotation();return rotation != null ? rotation.getOrientationListener() : null;}@Overridepublic void onDown() {final WindowOrientationListener listener = getOrientationListener();if (listener != null) {listener.onTouchStart();}}@Overridepublic void onUpOrCancel() {final WindowOrientationListener listener = getOrientationListener();if (listener != null) {listener.onTouchEnd();}}@Overridepublic 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 */);}@Overridepublic 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 */);}@Overridepublic void onMouseLeaveFromEdge() {mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);}});Android12源代码mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler,new SystemGesturesPointerEventListener.Callbacks() {@Overridepublic void onSwipeFromTop() {synchronized (mLock) {if (mStatusBar != null) {requestTransientBars(mStatusBar);}checkAltBarSwipeForTransientBars(ALT_BAR_TOP);}}@Overridepublic 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);}}@Overridepublic 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();}@Overridepublic 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();}@Overridepublic void onFling(int duration) {if (mService.mPowerManagerInternal != null) {mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, duration);}}@Overridepublic void onDebug() {// no-op}private WindowOrientationListener getOrientationListener() {final DisplayRotation rotation = mDisplayContent.getDisplayRotation();return rotation != null ? rotation.getOrientationListener() : null;}@Overridepublic void onDown() {final WindowOrientationListener listener = getOrientationListener();if (listener != null) {listener.onTouchStart();}}@Overridepublic void onUpOrCancel() {final WindowOrientationListener listener = getOrientationListener();if (listener != null) {listener.onTouchEnd();}}@Overridepublic 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 */);}@Overridepublic 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 */);}@Overridepublic void onMouseLeaveFromEdge() {mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);}});
由于我们需要实现的是手势上滑隐藏导航栏,故只需关注onSwipeFromBottom方法,在其中触发事件时发送对应事件,然后载在SystemUI中接收对应事件实现隐藏显示效果。我直接在onSwipeFromBottom发送广播。
@Overridepublic 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@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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.javaAndroid12 路径
frameworks/base/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerpublic 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);}}