为什么应用要适配多窗口
鸿蒙系统支持全屏、分屏、自由窗口、悬浮窗多种形态,手机折叠屏展开时还会从竖屏变成接近方形的窗口。应用如果只按全屏手机设计,进了分屏会挤、进了平板会空,观感差很多。
好应用不是画一套手机 UI,而是跟着窗口形态呼吸。
系统默认大多数应用都支持多窗口,你不适配,用户也会把应用拖进分屏——然后看到一排排被截断的文字。与其被动出问题,不如主动适配。这篇从窗口管理讲起,到布局自适应,最后用一个列表页实战收尾。
适配的关键不是每个窗口写一套页面,而是让布局、字号、间距对窗口尺寸敏感。窗口变窄,列表和详情自动变成上下结构;窗口变宽,自动变成左右分栏。掌握了这套思路,手机、平板、折叠屏一次通吃。
窗口能力与窗口管理
应用的窗口由 WindowStage 管理。通过 getMainWindow 拿到主窗口,可以查询窗口属性、监听窗口尺寸变化,还能设置窗口布局模式。
import { window } from '@kit.ArkUI';
onWindowStageCreate(stage: window.WindowStage) {
const mainWin = stage.getMainWindowSync();
const props = mainWin.getWindowProperties();
console.log('窗口尺寸', props.windowRect.width, props.windowRect.height);
}
- WindowStage窗口生命周期入口。
- getMainWindow拿主窗口改属性。
- 窗口事件尺寸变化、焦点变化都能监听。
分屏与自由窗口适配
分屏时窗口被压到一半甚至四分之一宽,自由窗口更小。这时候要监听尺寸变化,动态调整内容密度:小窗口隐藏次要信息、缩小间距、简化导航。
mainWin.on('windowSizeChange', (newSize) => {
const narrow = newSize.width < 600;
this.pageModel.updateLayout(narrow ? 'compact' : 'expanded');
});
窗口高度也要管:自由窗口可能只有半屏高,长列表要优先显示顶部内容,底部操作栏固定不滚走。键盘弹起时还要留出安全区,别让输入框被窗口边缘吃掉。
布局自适应
ArkUI 推荐用栅格 GridRow 做自适应布局,配合断点把界面分成 1 栏、2 栏、4 栏。窗口宽度变化时栅格自动重排,不用写一堆媒体查询。
折叠屏还要处理展开态和折叠态的切换:展开时从竖屏变横屏,布局立刻重排,动画别闪。用 onBreakpointChange 监听断点变化,在切换瞬间更新布局状态。
多窗口生命周期与数据共享
应用进了分屏或自由窗口,生命周期和全屏一样走 onForeground、onBackground。窗口之间没有真正的多开,一个应用还是同一份实例,数据天然共享。
onWindowStageEvent(event: window.WindowStageEventType) {
if (event === window.WindowStageEventType.SHOWN) this.refreshData();
if (event === window.WindowStageEventType.ACTIVE) this.bindActive();
}
窗口变窄后组件重新布局,状态要留在 ViewModel 或 AppStorage 里,别放在组件局部变量中,否则重排时数据就丢了。这是多窗口适配最隐蔽的坑。
实战:列表页适配分屏
做一个新闻列表页:全屏时列表占满,宽窗口时左侧列表右侧详情,窄窗口时点列表项再进详情。
build() {
GridRow({ columns: this.layoutModel.columns }) {
GridCol({ span: { sm: 12, md: 6, lg: 5 } }) { this.buildList() }
GridCol({ span: { sm: 12, md: 6, lg: 7 } }) { this.buildDetail() }
}
}
断点映射:窗口窄于 600 用单列,600 到 840 用两列,超过 840 用四列。列表项高度不要写死,让卡片自适应。详情页在小窗口时作为独立页面跳转,宽窗口时内嵌显示。
小结
多窗口适配三板斧:监听窗口尺寸、用栅格做响应式、状态放全局。小窗口收敛信息、大窗口展开分栏,配合折叠屏断点切换,一套代码跑遍手机平板。用户把应用拖进分屏的那一刻,就是验收时刻。