应用在三折叠设备的单屏态(F态)、双屏态(M态)和三屏态(G态)上运行时,会出现内容显示异常的现象。在折叠态切换过程中(如从G态切换到F态),还可能出现布局卡顿现象:一次折叠动作会触发多次on('windowSizeChange')和windowModeChange回调,系统过渡动画与应用内布局重算争抢主线程,导致动画帧率明显下降,切换完成后可能出现短暂白屏。
应用没有通过getWindowWidthBreakpoint()与getWindowHeightBreakpoint()获取当前窗口横向断点与纵向断点。未通过on('windowSizeChange')方法监听窗口尺寸变化,并在监听回调中重新获取断点,及时更新页面布局,导致页面显示异常。即使已监听on('windowSizeChange')事件,若未对回调进行节流处理,折叠态切换过程中频繁触发的回调会导致布局反复重算,与系统过渡动画争抢主线程,引起卡顿和短暂白屏。
建议参照官方示例实现断点触发的UI刷新,具体步骤如下:
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
const BP_SM_MAX = 600;
const BP_MD_MAX = 840;
const RESIZE_THROTTLE_MS = 150;
@Entry
@ComponentV2
struct AdaptivePage {
@Local breakpoint: 'sm' | 'md' | 'lg' = 'sm';
@Local navMode: NavigationMode = NavigationMode.Stack;
private resizeTimer: number = -1;
private pendingWidth: number = 0;
private navStack: NavPathStack = new NavPathStack();
private win?: window.Window;
aboutToAppear(): void {
window.getLastWindow(this.getUIContext().getHostContext()).then(w => {
this.win = w;
try {
const prop = w.getWindowProperties();
this.applyBreakpoint(prop.windowRect.width);
w.on('windowSizeChange', (data: window.Size) => {
this.pendingWidth = data.width;
// 节流:150ms内只执行最后一次
if (this.resizeTimer !== -1) {
clearTimeout(this.resizeTimer);
}
this.resizeTimer = setTimeout(() => {
this.applyBreakpoint(this.pendingWidth);
this.resizeTimer = -1;
}, RESIZE_THROTTLE_MS);
});
} catch (err) {
hilog.error(0x0000, 'AdaptivePage', `getWindowProperties or on failed: ${err}`);
}
})
}
aboutToDisappear(): void {
if (this.win) {
this.win.off('windowSizeChange');
}
if (this.resizeTimer !== -1) {
clearTimeout(this.resizeTimer);
this.resizeTimer = -1;
}
}
private applyBreakpoint(width: number): void {
const newBp = width <= BP_SM_MAX ? 'sm' : width <= BP_MD_MAX ? 'md' : 'lg';
const newMode = width <= BP_SM_MAX ? NavigationMode.Stack : NavigationMode.Split;
// 仅在断点真正变化时更新,避免重复渲染
if (newBp !== this.breakpoint) {
this.breakpoint = newBp;
}
if (newMode !== this.navMode) {
this.navMode = newMode;
}
}
build() {
Navigation(this.navStack) {
GridRow({
breakpoints: {
value: ['200vp', '300vp', '400vp', '500vp', '600vp'],
reference: BreakpointsReference.WindowSize
}
}) {
ForEach(['rgb(39,135,217)'], (color: ResourceColor, index?: number | undefined) => {
GridCol({
span: {
sm: 4, md: 8, lg: 12
}
}) {
Row() {
Text(`${"半屏布局"}`)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.width("100%")
}
.width("100%")
.height('80vp')
.justifyContent(FlexAlign.Center)
}.backgroundColor(color)
})
}
}
.mode(this.navMode)
}
}