在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.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);
}
}