在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源码分析
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);
}
});
由于我们需要实现的是手势上滑隐藏导航栏,故只需关注onSwipeFromBottom方法,在其中触发事件时发送对应事件,然后载在SystemUI中接收对应事件实现隐藏显示效果。我直接在
@Override
public void onSwipeFromBottom() {
synchronized (mLock) {
if (mNavigationBar != null
&& mNavigationBarPosition == NAV_BAR_BOTTOM) {
//自定义上滑广播
mContext.sendBroadcast(new Intent("com.android.action.swipefrombottom")); //自定义上滑广播
//自定义上滑广播
requestTransientBars(mNavigationBar);
}
checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
}
}
3.实现如下
--- a/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java
import com.android.server.policy.WindowOrientationListener;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wallpaper.WallpaperManagerInternal;
import com.android.server.wm.utils.InsetUtils;
+import android.util.Log;
import java.io.PrintWriter;
//unisoc: For Power Hint
import android.os.PowerHintVendorSprd;
public class DisplayPolicy extends AbsDisplayPolicy {
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
+ //mContext.sendBroadcast(new Intent("com.android.action.swipefromtop"));
}
@Override
public class DisplayPolicy extends AbsDisplayPolicy {
updateShowHideNavSettings(true);
}
}
//自定义上滑广播
+ mContext.sendBroadcast(new
Intent("com.android.action.swipefrombottom"));
+ Log.e("StatusBar","onSwipeFromBottom");
}
3 StatusBar监听自定义广播然后实现导航栏显示和隐藏功能
--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -673,7 +673,7 @@ public class StatusBar extends SystemUI implements DemoMode,
};
private ActivityIntentHelper mActivityIntentHelper;
private ShadeController mShadeController;
+ private boolean navigationBarState = false;
-
+ private RegisterStatusBarResult result = null;
@Override
public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
Dependency.get(MAIN_HANDLER).post(() -> {
@@ -779,7 +779,6 @@ public class StatusBar extends SystemUI implements DemoMode,
mCommandQueue = getComponent(CommandQueue.class);
mCommandQueue.addCallback(this);
- RegisterStatusBarResult result = null;
try {
result = mBarService.registerStatusBar(mCommandQueue);
} catch (RemoteException ex) {
@@ -824,6 +823,8 @@ public class StatusBar extends SystemUI implements DemoMode,
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);
@@ -963,7 +964,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationLogger.setHeadsUpManager(mHeadsUpManager);
putComponent(HeadsUpManager.class, mHeadsUpManager);
- createNavigationBar(result);
+ //createNavigationBar(result);
if (ENABLE_LOCKSCREEN_WALLPAPER) {
mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
@@ -4515,7 +4516,19 @@ public class StatusBar extends SystemUI implements DemoMode,
);
}
- }
+ }else if("com.android.action.swipefrombottom".equals(action)){
+ //上滑事件 android.util.Log.d("StatusBar","swipefrombottom-----");
+ if(!navigationBarState = false){
+ navigationBarState = true;
//加载导航栏
+ createNavigationBar(result);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
// 移除导航栏
+ mNavigationBarController.removeNavigationBar(mDisplayId);
+ }
+ },3000);
+ }
+ }else if("com.android.action.swipefromtop".equals(action)){
+ android.util.Log.d("StatusBar","swipefromtop---");
+ 下滑事件
//mNavigationBarController.removeNavigationBar(mDisplayId);
+ }
}
};
在 StatusBar的makeStatusBarView中去掉加载导航栏的方法createNavigationBar(result)而在start()方法中监听系统手势上滑的自定义广播,然后在收到自定义广播后,弹出系统导航栏,三秒钟后消失导航栏
4.修改隐藏导航栏方法
--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -164,7 +164,7 @@ public class NavigationBarController implements Callbacks {
});
}
//隐藏导航栏方法变为public 方便调用
- private void removeNavigationBar(int displayId) {
+ public void removeNavigationBar(int displayId) {
NavigationBarFragment navBar = mNavigationBars.get(displayId);
if (navBar != null) {
View navigationWindow = navBar.getView().getRootView();