WindowStage 多窗口与沉浸式窗口实践:从适配到体验细节
窗口体验不是简单地"铺满屏幕"。横竖屏、折叠屏、平板分屏、沉浸式状态栏、弹窗窗口都会影响用户感受。Stage 模型下,窗口管理集中在 WindowStage 和 Window 对象上,工程代码要把布局适配和业务页面解耦。

本文用一个内容阅读类应用做例子:手机全屏阅读、平板左右分栏、沉浸式图片预览、弹窗确认,都通过统一的窗口策略管理。


1. 先建立窗口场景模型
窗口适配不要直接写一堆 if width > xxx。先把窗口场景抽象出来,页面只关心当前是紧凑、普通还是宽屏。
ts
export enum WindowSizeClass {
Compact = 'compact',
Medium = 'medium',
Expanded = 'expanded'
}
export function resolveSizeClass(widthVp: number): WindowSizeClass {
if (widthVp < 600) {
return WindowSizeClass.Compact;
}
if (widthVp < 840) {
return WindowSizeClass.Medium;
}
return WindowSizeClass.Expanded;
}
代码解释:
- 阈值集中在一个函数里,方便后续跟设计规范同步。
- 页面只使用
WindowSizeClass,不直接依赖具体像素。 - 平板、折叠屏、分屏都可以复用这套判断。
2. 监听窗口尺寸变化
用户拖动分屏或旋转设备时,窗口尺寸会变化。页面应响应尺寸类变化,而不是只在启动时判断一次。
ts
import { window } from '@kit.ArkUI';
export class WindowSizeStore {
private static sizeClass: WindowSizeClass = WindowSizeClass.Compact;
static update(mainWindow: window.Window): void {
const rect = mainWindow.getWindowProperties().windowRect;
WindowSizeStore.sizeClass = resolveSizeClass(rect.width);
}
static current(): WindowSizeClass {
return WindowSizeStore.sizeClass;
}
}
代码解释:
- 从窗口属性读取宽度,统一转换为尺寸类。
- 页面通过 store 读取当前状态,避免各自访问窗口对象。
- 如果项目使用状态管理,可以把这里改成可观察状态。
3. 沉浸式状态栏要按页面设置
不是所有页面都适合沉浸式。图片预览页需要沉浸,表单页可能不需要。建议把沉浸式配置做成页面策略。
ts
export interface ImmersiveConfig {
enabled: boolean;
statusBarColor: string;
navigationBarColor: string;
lightIcon: boolean;
}
export const immersiveRules: Record<string, ImmersiveConfig> = {
Home: { enabled: false, statusBarColor: '#FFFFFF', navigationBarColor: '#FFFFFF', lightIcon: false },
Reader: { enabled: true, statusBarColor: '#00000000', navigationBarColor: '#00000000', lightIcon: true },
ImagePreview: { enabled: true, statusBarColor: '#00000000', navigationBarColor: '#000000', lightIcon: true }
};
代码解释:
- 沉浸式按页面配置,避免全局一刀切。
- 透明状态栏适合图片、阅读等内容型页面。
- 图标明暗要和背景搭配,否则状态栏会看不清。
4. 应用沉浸式配置
获取主窗口后,根据当前页面应用窗口属性。实际项目中这段可以放在页面进入时调用。
ts
export class ImmersiveWindowService {
static async apply(pageName: string, mainWindow: window.Window): Promise<void> {
const config = immersiveRules[pageName] ?? immersiveRules.Home;
await mainWindow.setWindowLayoutFullScreen(config.enabled);
await mainWindow.setWindowSystemBarProperties({
statusBarColor: config.statusBarColor,
navigationBarColor: config.navigationBarColor,
statusBarContentColor: config.lightIcon ? '#FFFFFF' : '#111111',
navigationBarContentColor: config.lightIcon ? '#FFFFFF' : '#111111'
});
}
}
代码解释:
setWindowLayoutFullScreen控制内容是否延伸到系统栏区域。- 系统栏颜色和图标颜色要成组设置。
- 没有配置的页面回到 Home 规则,避免继承上一个页面的沉浸式状态。
5. 宽屏页面不要只是拉伸
平板或横屏下,如果只是把手机页面拉宽,阅读体验会变差。宽屏场景应该使用分栏或居中最大宽度。
ts
export function resolveReaderLayout(sizeClass: WindowSizeClass): string {
switch (sizeClass) {
case WindowSizeClass.Expanded:
return 'twoColumn';
case WindowSizeClass.Medium:
return 'centerMaxWidth';
default:
return 'singleColumn';
}
}
代码解释:
- 宽屏采用双栏,利用横向空间。
- 中等宽度居中限制最大宽度,避免行长过长。
- 手机保持单栏,减少操作复杂度。
6. 弹窗窗口要控制尺寸和焦点
确认弹窗、筛选面板、分享面板都不应该直接占满全屏。窗口策略可以统一控制弹层尺寸、圆角和焦点行为。
ts
export interface DialogWindowOptions {
widthVp: number;
heightVp: number;
focusable: boolean;
}
export function resolveDialogOptions(sizeClass: WindowSizeClass): DialogWindowOptions {
if (sizeClass === WindowSizeClass.Expanded) {
return { widthVp: 520, heightVp: 420, focusable: true };
}
return { widthVp: 360, heightVp: 420, focusable: true };
}
代码解释:
- 弹窗尺寸随窗口场景变化,不在组件里写死。
focusable明确弹窗是否接收焦点。- 平板弹窗可以更宽,但仍要限制最大尺寸。
7. 窗口状态恢复要有默认值
窗口策略依赖运行时状态,但页面重建时状态可能为空。每个窗口配置都要有默认值。
ts
export class WindowProfile {
constructor(
readonly sizeClass: WindowSizeClass = WindowSizeClass.Compact,
readonly immersive: ImmersiveConfig = immersiveRules.Home
) {}
static fallback(): WindowProfile {
return new WindowProfile();
}
}
代码解释:
- 默认紧凑布局保证手机场景优先可用。
- 默认非沉浸式,避免系统栏文字不可见。
- 恢复失败时使用
fallback,页面至少能正常展示。
8. 调试窗口问题要记录尺寸和页面
窗口适配问题经常只在某些设备出现。日志里必须有页面名、窗口宽高、尺寸类、沉浸式状态。
ts
export function logWindowProfile(page: string, width: number, height: number): void {
const sizeClass = resolveSizeClass(width);
hilog.info(
0x20260702,
'WindowProfile',
'page=%{public}s width=%{public}d height=%{public}d class=%{public}s',
page,
width,
height,
sizeClass
);
}
代码解释:
- 没有宽高日志,适配问题很难远程复现。
- 记录尺寸类能验证策略是否命中。
- 页面名用于判断是不是某个页面漏应用窗口规则。
9. 验收清单
| 场景 | 检查点 |
|---|---|
| 手机竖屏 | 单栏、状态栏清晰 |
| 手机横屏 | 内容不被系统栏遮挡 |
| 平板分屏 | 尺寸变化后布局刷新 |
| 图片预览 | 沉浸式生效,返回后恢复 |
| 弹窗 | 宽屏不拉满,焦点正确 |
10. 小结
多窗口和沉浸式体验的关键是"页面不直接管理窗口细节"。把尺寸类、沉浸式规则、弹窗尺寸和日志统一到窗口服务里,业务页面只根据策略渲染内容。这样应用从手机扩展到平板、折叠屏和分屏时,不需要重写一套页面。