本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、子窗口的核心作用
- 功能扩展:承载辅助功能(如弹窗、悬浮窗、画中画视频等)
- 多任务处理:允许主窗口和子窗口同时交互(如主窗口浏览,子窗口播放视频)
- 数据通信:通过AppStorage或事件机制实现主窗口与子窗口数据同步
- 灵活布局:可自定义位置、大小和层级(如可拖拽的悬浮窗)
二、创建子窗口的完整步骤
1. 获取WindowStage对象
在Ability中传递窗口实例到页面:
// EntryAbility.ets
onWindowStageCreate(windowStage: window.WindowStage) {
windowStage.loadContent('pages/Index');
AppStorage.setOrCreate('windowStage', windowStage); // 存储到全局
}
2. 创建子窗口
通过createSubWindow
方法创建并配置:
// Index.ets
import { window } from '@ohos.window';
let subWindow: window.Window | undefined = undefined;
@Entry
@Component
struct Index {
@State message: string = '主窗口';
private createSubWindow() {
const windowStage = AppStorage.get('windowStage');
windowStage?.createSubWindow("mySubWindow", (err, data) => {
if (err.code) {
console.error('创建失败:', err);
return;
}
subWindow = data;
// 设置子窗口属性
subWindow.moveWindowTo(300, 300); // 位置
subWindow.resize(500, 500); // 大小
subWindow.setUIContent("pages/SubPage", (err) => { // 加载内容
subWindow?.showWindow(); // 显示窗口
});
});
}
build() {
Column() {
Button('创建子窗口')
.onClick(() => this.createSubWindow())
}
}
}
3. 子窗口页面开发
// SubPage.ets
@Entry
@Component
struct SubPage {
@State text: string = '子窗口内容';
build() {
Column() {
Text(this.text)
.onClick(() => {
this.text = '点击更新!';
})
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
4. 销毁子窗口
private destroySubWindow() {
subWindow?.destroyWindow((err) => {
if (!err.code) console.log('销毁成功');
});
}
三、高级功能实现
1. 拖拽交互
通过手势事件移动窗口
// SubPage.ets
@State @Watch('onMove') posX: number = 300;
@State @Watch('onMove') posY: number = 300;
onMove() {
subWindow?.moveWindowTo(this.posX, this.posY);
}
build() {
Column()
.gesture(
GestureGroup(GestureMode.Exclusive, [
PanGesture({ direction: PanDirection.All })
.onActionUpdate((event: GestureEvent) => {
this.posX += event.offsetX;
this.posY += event.offsetY;
})
])
)
}
2. 主窗口与子窗口通信
方式一:AppStorage双向绑定
// 主窗口
@StorageLink('sharedData') sharedText: string = '默认';
// 子窗口
@StorageLink('sharedData') subText: string;
方式二:EventHub事件总线
// 主窗口发布事件
getContext(this).eventHub.emit('update', { data: '新数据' });
// 子窗口监听
getContext(this).eventHub.on('update', (data) => {
this.text = data.data;
});
3. 悬浮窗样式优化
subWindow?.setWindowBackgroundColor('#00000000'); // 透明背景
subWindow?.setWindowLayoutFullScreen(false); // 非全屏
subWindow?.setWindowBrightness(0.8); // 亮度调节
四、完整示例:视频画中画
// 1. 创建视频悬浮窗
createVideoWindow() {
this.windowStage.createSubWindow("videoWindow", (err, win) => {
win.resize(300, 200);
win.moveWindowTo(screenWidth - 320, screenHeight - 220);
win.setUIContent("pages/VideoPage", () => {
win.showWindow();
});
});
}
// 2. VideoPage.ets中实现播放控制
@Entry
@Component
struct VideoPage {
@State isPlaying: boolean = true;
build() {
Column() {
VideoPlayer({ src: 'video.mp4' })
.controls(false)
.autoPlay(true)
Button(this.isPlaying ? '暂停' : '播放')
.onClick(() => this.isPlaying = !this.isPlaying)
}
}
}
五、注意事项
- 权限声明:系统级悬浮窗需申请权限
"requestPermissions": [ { "name": "ohos.permission.SYSTEM_FLOAT_WINDOW" } ]
- 性能优化:避免频繁创建/销毁窗口,建议复用实例
- 兼容性:子窗口最小尺寸为320x240vp,最大2560x2560vp
- 生命周期:子窗口不会出现在任务管理中,需手动管理销毁