智能客服
你问我答,随时在线为你解决问题

























算法研究小天才应用悬浮窗小窗口形态下,点击小窗口,使应用窗口从悬浮窗小窗口形态转换至悬浮窗正常态时,顶部控制条遮挡,全屏窗口模式与悬浮窗模式间进行切换则不会出现该情况。


【背景知识】
开发应用沉浸式时,可以通过调用窗口强制全屏布局接口setWindowLayoutFullScreen()实现界面元素延伸到状态栏和导航区域;然后通过接口getWindowAvoidArea()和on('avoidAreaChange')获取并动态监听避让区域的变更信息,页面布局根据避让区域信息进行动态调整。
on('windowSizeChange')接口用于开启窗口尺寸变化的监听,on('windowStatusChange')接口用于开启窗口模式变化的监听,当窗口windowStatus发生变化时进行通知。
【问题定位】
查看EntryAbility.ets文件中,应用是如何动态监听并更新避让区域的变更的,发现应用采用on('windowSizeChange')或on('windowStatusChange')接口进行监听,而非采用on('avoidAreaChange')接口。
windowClass.on('windowSizeChange',(size) => {
let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR;
let avoidArea = windowClass.getWindowAvoidArea(type);
AppStorage.setOrCreate('avoidArea',avoidArea);
let bottomRectHeight = avoidArea.bottomRect.height;
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
type = window.AvoidAreaType.TYPE_SYSTEM;
avoidArea = windowClass.getWindowAvoidArea(type);
AppStorage.setOrCreate('avoidArea',avoidArea);
let topRectHeight = avoidArea.topRect.height;
AppStorage.setOrCreate('topRectHeight', topRectHeight);
})
windowClass.on('windowStatusChange', (WindowStatusType) => {
let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR;
let avoidArea = windowClass.getWindowAvoidArea(type);
AppStorage.setOrCreate('avoidArea',avoidArea);
let bottomRectHeight = avoidArea.bottomRect.height;
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
type = window.AvoidAreaType.TYPE_SYSTEM;
avoidArea = windowClass.getWindowAvoidArea(type);
AppStorage.setOrCreate('avoidArea',avoidArea);
let topRectHeight = avoidArea.topRect.height;
AppStorage.setOrCreate('topRectHeight', topRectHeight);
});
查看两种监听接口在应用窗口从悬浮窗小窗口形态转换至悬浮窗正常态时的日志输出情况,对比全屏窗口模式与悬浮窗模式间进行切换时,从悬浮窗小窗模式变为默认悬浮窗大小(包括悬浮窗状态下改变窗口尺寸)不会触发on('windowSizeChange')或on('windowStatusChange')接口进行监听。
windowClass.on('windowSizeChange',(size) => {
// To do sth.
console.info('成功更新避让区高度变化:Succeeded in refresh the avoid area changes.');
console.info('成功监听窗口尺寸变化:Succeeded in enabling the listener for window size changes.');
})
windowClass.on('windowStatusChange', (WindowStatusType) => {
// To do sth.
console.info('成功监听窗口模式变化:Succeeded in enabling the listener for window status changes.');
});

【分析结论】
应用采用on('windowSizeChange')或on('windowStatusChange')接口进行监听并更新避让区高度,而非采用on('avoidAreaChange')接口,由于从悬浮窗小窗模式变为默认悬浮窗大小(包括悬浮窗状态下改变窗口尺寸)不会触发on('windowSizeChange')或on('windowStatusChange')接口进行监听,所以不会触发避让区高度更新,因此应用窗口从悬浮窗小窗口形态转换至悬浮窗正常态时,顶部控制条遮挡。
【修改建议】
建议采用on('avoidAreaChange')接口开启当前应用窗口系统规避区变化的监听,以实现动态监听避让区域的变更信息,页面布局根据避让区域信息进行动态调整。
windowClass.on('avoidAreaChange', (data) => {
if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
let topRectHeight = data.area.topRect.height;
AppStorage.setOrCreate('topRectHeight', topRectHeight);
} else if (data.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {
let bottomRectHeight = data.area.bottomRect.height;
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
}
});
完整代码如下:
// EntryAbility.ets
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
const DOMAIN = 0x0000;
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created,set main page for this ability
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
});
let windowClass: window.Window = windowStage.getMainWindowSync(); // 获取应用主窗口
// 1.设置窗口全屏
let isLayoutFullScreen = true;
windowClass.setWindowLayoutFullScreen(isLayoutFullScreen).then(() => {
console.info('Succeeded in setting the window layout to full-screen mode.');
}).catch((err: BusinessError) => {
console.error(`Failed to set the window layout to full-screen mode. Code is ${err.code}, message is ${err.message}`);
});
// 2.获取布局避让遮挡的区域
let type = window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR; // 此处以导航条避让为例
let avoidArea = windowClass.getWindowAvoidArea(type);
let bottomRectHeight = avoidArea.bottomRect.height; // 获取到导航区域的高度
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
type = window.AvoidAreaType.TYPE_SYSTEM; // 以状态栏避让为例
avoidArea = windowClass.getWindowAvoidArea(type);
let topRectHeight = avoidArea.topRect.height; // 获取状态栏区域高度
AppStorage.setOrCreate('topRectHeight', topRectHeight);
// 3.注册监听函数,动态获取避让区域数据
windowClass.on('avoidAreaChange', (data) => {
if (data.type === window.AvoidAreaType.TYPE_SYSTEM) {
let topRectHeight = data.area.topRect.height;
AppStorage.setOrCreate('topRectHeight', topRectHeight);
} else if (data.type === window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR) {
let bottomRectHeight = data.area.bottomRect.height;
AppStorage.setOrCreate('bottomRectHeight', bottomRectHeight);
}
});
}
onWindowStageDestroy(): void {
// Main window is destroyed,release UI related resources
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
}
}
// Index.ets
@Entry
@Component
struct Index {
@StorageProp('bottomRectHeight')
bottomRectHeight: number = 0;
@StorageProp('topRectHeight')
topRectHeight: number = 0;
build() {
Column() {
Row() {
Text('Top Content').fontSize(40).textAlign(TextAlign.Center).width('100%')
}.backgroundColor('#2786d9')
Row() {
Text('Display Content 2').fontSize(30)
}.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%')
Row() {
Text('Display Content 3').fontSize(30)
}.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%')
Row() {
Text('Display Content 4').fontSize(30)
}.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%')
Row() {
Text('Display Content 5').fontSize(30)
}.backgroundColor(Color.White).padding(20).borderRadius(15).width('80%')
Row() {
Text('Bottom Content').fontSize(40).textAlign(TextAlign.Center).width('100%')
}.backgroundColor('#96dffa')
}
.width('100%').height('100%')
.alignItems(HorizontalAlign.Center)
.backgroundColor('#d5d5d5')
.justifyContent(FlexAlign.SpaceBetween)
// top数值与状态栏区域高度保持一致;bottom数值与导航区域高度保持一致
.padding({
top: this.getUIContext().px2vp(this.topRectHeight),
bottom: this.getUIContext().px2vp(this.bottomRectHeight)
})
}
}
我要提问题
HarmonyOS 切换为悬浮窗后web页面布局问题 (API12+)
HarmonyOS 如何后台拉起悬浮窗 (API12+)
HarmonyOS PC上应用启动悬浮窗,系统没有显示,如何解决?(API12+)
HarmonyOS 悬浮窗和应用内通知实现问题 (API12+)
点击切换悬浮窗按钮,应用从全屏模式切换成悬浮窗模式时响应慢
如何判断应用上层是否存在悬浮窗遮挡
HarmonyOS 全屏悬浮窗遮挡浏览器等应用窗口 (API12+)
悬浮窗拉起的子窗覆盖其他应用窗口如何解决
智能客服
你问我答,随时在线为你解决问题
合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
解决方案
精准高效的一站式服务支持,助力开发者商业成功