深圳设计网站培训seo网站优化方案
harmony OS NEXT-沉浸式布局实现笔记
沉浸式布局核心原理
产生白边问题的原因
区域类型 | 分辨率 | 安全区偏移量 | 系统组件 |
---|---|---|---|
状态栏 | 1280*60px | TOP: 60vp | 电池、信号、时间等 |
手势条区域 | 1280*120px | BOTTOM: 48vp | 返回手势指示条 |
方法一:窗口全局全屏 + 安全区动态适配
1. 启用全屏模式
// entryability/EntryAbility.ts
import window from '@ohos.window';export default class EntryAbility extends Ability {async onWindowStageCreate(windowStage: window.WindowStage) {try {const win = await windowStage.getMainWindow();await win.setWindowLayoutFullScreen(true); // 启用全屏布局this.setupAvoidAreaListeners(win); // 安全区变化监听} catch (err) {console.error('全屏模式设置失败:', err);}}private setupAvoidAreaListeners(win: window.Window) {win.on('avoidAreaChange', (area: window.AvoidArea) => {AppStorage.setOrCreate<AvoidAreaModel>('avoidArea', new AvoidAreaModel(area.topRect, area.bottomRect));});}
}
2. 安全区数据模型
// model/AvoidAreaModel.ts
export class AvoidAreaModel {topHeight: number = 0; // VP单位bottomHeight: number = 0;constructor(topRect: rectangle.Rect, bottomRect: rectangle.Rect) {this.topHeight = px2vp(topRect.height);this.bottomHeight = px2vp(bottomRect.height);}
}
3. UI层安全区适配组件
// components/SafeAreaContainer.ets
@Component
struct SafeAreaContainer {@StorageLink('avoidArea') avoidArea: AvoidAreaModel = new AvoidAreaModel();build() {Column() {// 自定义内容通过slot插入Slot()}.padding({ top: this.avoidArea.topHeight,bottom: this.avoidArea.bottomHeight }).backgroundColor(Color.Transparent).onAppear(() => {this.checkAvoidAreaValidity();})}private checkAvoidAreaValidity() {if (this.avoidArea.topHeight === 0) {console.warn('安全区高度未正确初始化,请检查window监听');}}
}
方法二:组件级区域控制(推荐方案)
1. 整合安全区功能的装饰器
// decorators/WithSafeArea.ts
export function WithSafeArea<T extends Object>(WrappedComponent: new () => T) {@Componentstruct WrapperComponent {@State avoidArea: AvoidAreaModel = AppStorage.get('avoidArea');async aboutToAppear() {this.updateAvoidArea(); // 初次加载获取当前安全区}private async updateAvoidArea() {try {const win = await window.getTopWindow();const area = await win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM);this.avoidArea = new AvoidAreaModel(area.topRect, area.bottomRect);} catch (error) {console.error('安全区获取失败:', error);}}build() {Column() {WrappedComponent()}.padding({top: this.avoidArea.topHeight,bottom: this.avoidArea.bottomHeight})}}return WrapperComponent;
}
2. 使用示例
@Entry
@WithSafeArea
struct HomePage {build() {Column() {Text('主内容区域').fontSize(20).fontColor(Color.White)}.width('100%').height('100%').backgroundColor('#FF409EFF')}
}
方案对比与最佳实践
对比维度 | 全局窗口方案 | 组件级方案 |
---|---|---|
性能消耗 | 中等(全局监听) | 低(按需加载) |
代码侵入性 | 高(需修改Ability) | 低(装饰器模式) |
动态更新支持 | 自动响应 | 需手动刷新 |
多窗口场景支持 | 部分支持 | 完全支持 |
推荐应用场景 | 全App沉浸式风格统一 | 特定页面定制化需求 |
开发建议:
-
在API version ≥ 9时优先使用
window.getWindowAvoidArea
接口 -
涉及横竖屏切换时添加防抖处理:
let resizeTimer: number = 0;win.on('windowSizeChange', () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(() => this.updateAvoidArea(), 300);});
-
在原子化服务场景中应与enterFullScreen方法结合使用