系统和硬件环境:OpenHarmony5.0.0, 硬件RK3566
需求:实现全局中导航栏、状态栏和下拉栏的隐藏和显示
问题描述:在SystemUI中实现了一个控制器,专门用于控制导航栏、下拉栏和状态栏的显示和隐藏,功能看上去好像实现了,但是存在两个问题
1. 这个控制中心应该放在哪里?当要对这些组件进行控制的时候,需要一个载体让用户可以按需设置,是悬浮、桌面应用还是系统设置里面的选项。尝试了改造下拉栏的通知栏,但是如果禁用了下拉栏不能返回控制中心,使用上存在局限性;
2. 打开最近任务栏后,隐藏失效。在控制中心完成设置后,从屏幕底部向上滑动可以返回桌面,此时桌面和打开其他应用时,状态栏和导航栏均可以隐藏。但是当从屏幕右侧底部向上滑动时会打开最近任务栏(应该是launcher的组件),通过手势返回桌面后,隐藏的导航栏和状态栏显示了。
控制器代码如下所示:
export const SYSTEMUI_VISIBILITY_CHANGE = 'SystemUIVisibilityChange';
export interface SystemUIState {
statusBarVisible: boolean;
navigationBarVisible: boolean;
dropdownEnabled: boolean;
kioskModeEnabled: boolean;
}
class SystemUIController {
private currentState: SystemUIState = {
statusBarVisible: true,
navigationBarVisible: true,
dropdownEnabled: true,
};
init(): void {
Log.showInfo(TAG, 'SystemUIController initializing...');
this.updateAppStorage();
Log.showInfo(TAG, 'SystemUIController initialized successfully');
}
private updateAppStorage(): void {
AppStorage.SetOrCreate('statusBarVisible', this.currentState.statusBarVisible);
AppStorage.SetOrCreate('navigationBarVisible', this.currentState.navigationBarVisible);
AppStorage.SetOrCreate('dropdownEnabled', this.currentState.dropdownEnabled);
AppStorage.SetOrCreate('kioskModeEnabled', this.currentState.kioskModeEnabled);
}
private publishStateChange(): void {
EventManager.publish(obtainLocalEvent(SYSTEMUI_VISIBILITY_CHANGE, {
state: { ...this.currentState }
}));
Log.showDebug(TAG, `State changed: ${JSON.stringify(this.currentState)}`);
}
async showStatusBar(): Promise<void> {
Log.showInfo(TAG, 'Showing StatusBar');
this.currentState.statusBarVisible = true;
this.currentState.dropdownEnabled = true;
await WindowManager.showWindow(WindowType.STATUS_BAR);
this.updateAppStorage();
this.publishStateChange();
}
async hideStatusBar(): Promise<void> {
Log.showInfo(TAG, 'Hiding StatusBar');
this.currentState.statusBarVisible = false;
this.currentState.dropdownEnabled = false;
await WindowManager.hideWindow(WindowType.STATUS_BAR);
this.updateAppStorage();
this.publishStateChange();
}
async showNavigationBar(): Promise<void> {
Log.showInfo(TAG, 'Showing NavigationBar');
this.currentState.navigationBarVisible = true;
await WindowManager.showWindow(WindowType.NAVIGATION_BAR);
this.updateAppStorage();
this.publishStateChange();
}
async hideNavigationBar(): Promise<void> {
Log.showInfo(TAG, 'Hiding NavigationBar');
this.currentState.navigationBarVisible = false;
await WindowManager.hideWindow(WindowType.NAVIGATION_BAR);
this.updateAppStorage();
this.publishStateChange();
}
enableDropdown(): void {
if (this.currentState.statusBarVisible) {
Log.showInfo(TAG, 'Enabling Dropdown');
this.currentState.dropdownEnabled = true;
this.updateAppStorage();
this.publishStateChange();
} else {
Log.showWarn(TAG, 'Cannot enable dropdown: StatusBar is hidden');
}
}
disableDropdown(): void {
Log.showInfo(TAG, 'Disabling Dropdown');
this.currentState.dropdownEnabled = false;
this.updateAppStorage();
this.publishStateChange();
}
getState(): SystemUIState {
return { ...this.currentState };
}
async toggleStatusBar(): Promise<void> {
if (this.currentState.statusBarVisible) {
await this.hideStatusBar();
} else {
await this.showStatusBar();
}
}
async toggleNavigationBar(): Promise<void> {
if (this.currentState.navigationBarVisible) {
await this.hideNavigationBar();
} else {
await this.showNavigationBar();
}
}
}
let sSystemUIController = createOrGet(SystemUIController, TAG);
export default sSystemUIController as SystemUIController;
在隐藏和显示时都会调用WindowManager的show和hide函数,然后再调用window的show和hide函数。
查看这些组件代码,ServiceExtAbility中会实现窗口这些组件对应窗口的整个过程,创建之后显示,整个过程看上去都没有问题。但是我觉得我的控制逻辑实现上应该是存在问题的,查看了源码的事件管理,viewmodel等内容,查看了一下安卓上的实现方式:Android11动态设置显示隐藏导航栏 - M-kobe - 博客园 (cnblogs.com),虽然没看的太懂,但是感觉实现上应该不是很难,由于缺乏系统整体的把握,经常会陷入具体的实现细节上,还是没有找到一个合适的实现方式。
请教各位大佬给出一个实现思路,不胜感激!
1.或许你可以在设置中加一个 显示或隐藏的属性,然后对应的 设置systemui中导航栏NavigationBar和状态栏StatusBar的 高度 为0 或 非0 就能相对快速的解决你的问题。
2.当前 动态显隐 是更好的选择。
