【问题描述】
使用鸿蒙提供的@CustomDialog,实现弹窗,每次都要写很多重复性代码,想把CustomDialogController挂载到一个单例类中,方便代码复用。发现在class中封装了CustomDialogController的创建函数,弹窗无法弹起。
【原因】
CustomDialogController需要绑定一个ownerView。CustomDialogController定义在class或者静态方法中因缺少绑定关系,与UI组件没有任何关联关系导致拉不起弹窗,所以CustomDialogController需要定义在组件内。
【解决方案】
放弃@CustomDialog自定义弹窗
改用创建子窗口的方式创建弹窗,实现代码复用
【步骤】
- 在EntryAbility.ets中,使用 AppStorage 缓存 windowStage
async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
// ...
AppStorage.setOrCreate('windowStage', windowStage);
// ...
}
- 准备数据模型
interface BtnType {
label: string
code: string
color?: Color | string
autoClose?: boolean
callback: (type: string) => void
}
interface OptionsType {
title: string,
btnList: BtnType[]
}
- 在工具模块中,实现单例类 SubWinDialog
import { window } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit'
import { OptionsType } from '../pages/StyleDemo/models'
const windowStage: window.WindowStage | undefined = AppStorage.get('windowStage')
const mainWindowProperties = windowStage?.getMainWindowSync().getWindowProperties()
const mainWindowWidth = mainWindowProperties?.windowRect.width || 0
const mainWindowHeight = mainWindowProperties?.windowRect.height || 0
let subWindowClass: window.Window | null = null
export class SubWinDialog {
static open(options: OptionsType) {
if (!windowStage) return
AppStorage.setOrCreate('windowStageOptions', options)
// 1.创建子窗口
windowStage.createSubWindow('mySubWindow', (err: BusinessError, data) => {
if (err.code) return
subWindowClass = data
// 2.子窗口创建成功后,设置子窗口的位置、大小及相关属性等
subWindowClass.moveWindowTo(0, 0)
subWindowClass.resize(mainWindowWidth, mainWindowHeight)
subWindowClass.setWindowLayoutFullScreen(true)
// 3.为子窗口加载对应的目标页面
subWindowClass.setUIContent('pages/StyleDemo/SubWinPage', (err: BusinessError) => {
if (err.code) return
// 4.显示子窗口
(subWindowClass as window.Window).showWindow()
})
})
}
static close() {
const win = window.findWindow('mySubWindow') // 找到子窗口
win.destroyWindow() // 销毁窗口
}
}
- 第3步创建的子窗口需要加载一个页面,这个页面的样式就是我们弹窗的样式
import { window } from '@kit.ArkUI';
import { BtnType, OptionsType } from './models';
@Entry
@Component
struct SubWinPage {
@State message: string = 'Hello World';
@State options: OptionsType | undefined = undefined
aboutToAppear(): void {
this.options = AppStorage.get('windowStageOptions');
}
closeWin() {
const win = window.findWindow('mySubWindow') // 找到子窗口
win.destroyWindow() // 销毁窗口
}
build() {
Row() {
Column() {
Text(this.options?.title || '')
.layoutWeight(1)
Row() {
if (this.options?.btnList.length) {
ForEach(this.options.btnList, ((item: BtnType, index: number) => {
Text(item.label)
.border({
width: { left: index > 0 ? 0.5 : 0 },
color: Color.Gray
})
.testStyle()
.fontColor(item.color || Color.Black)
.onClick(() => {
item.callback(item.code)
item.autoClose && this.closeWin()
})
}))
}
}
.border({
width: { top: 0.5 },
color: Color.Gray
})
.height(50)
.width('100%')
}
.width('100%')
.height(200)
.backgroundColor(Color.White)
.borderRadius(8)
}
.height('100%')
.padding({ left: 50, right: 50 })
.backgroundColor("#60000000")
.onAppear(() => {
const win = window.findWindow('mySubWindow')
win.setWindowBackgroundColor("#00000000")
})
}
}
@Extend(Text)
function testStyle() {
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
.layoutWeight(1)
}
- 调用
import { SubWinDialog } from '../../utils'
import { promptAction } from '@kit.ArkUI'
import { BtnType } from './models'
@Entry
@Component
struct MainWinPage {
@State message: string = ''
btnList: BtnType[] = [{
label: '取消',
code: 'cancel',
autoClose: true,
callback: (type: string) => {
this.message = type
}
}, {
label: '验证',
code: 'confirm',
color: '#0a59f7',
callback: (type: string) => {
this.message = type
if (Math.random() > 0.5) {
promptAction.showToast({ message: '验证失败,请再次点击验证' })
return
}
SubWinDialog.close()
}
}]
build() {
Column({ space: 20 }) {
Text('测试弹窗页')
.width('100%')
.padding({ top: 50, bottom: 10 })
.fontSize(20)
.textAlign(TextAlign.Center)
.fontColor(Color.White)
.backgroundColor(Color.Green)
Text(`点击了:${this.message}`)
Button('显示弹窗')
.onClick(() => {
SubWinDialog.open({
title: '你好',
btnList: this.btnList
})
})
}
.width('100%')
.height('100%')
.backgroundColor(Color.Orange)
}
}
- 效果图