1# 不依赖UI组件的全局自定义弹窗 (推荐) 2 3 4由于[CustomDialogController](../reference/apis-arkui/arkui-ts/ts-methods-custom-dialog-box.md#customdialogcontroller)在使用上存在诸多限制,不支持动态创建也不支持动态刷新,在相对较复杂的应用场景中推荐使用UIContext中获取到的PromptAction对象提供的[openCustomDialog](../reference/apis-arkui/js-apis-arkui-UIContext.md#opencustomdialog12)接口来实现自定义弹窗。 5 6 7## 自定义弹窗的打开与关闭 8 91. 创建ComponentContent。 10 11 ComponentContent用于定义自定义弹窗的内容。其中,wrapBuilder(buildText)封装自定义组件,new Params(this.message)是自定义组件的入参,可以缺省,也可以传入基础数据类型。 12 13 ```ts 14 private contentNode: ComponentContent<Object> = new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message)); 15 ``` 16 172. 打开自定义弹窗。 18 19 通过调用openCustomDialog接口打开的弹窗默认为customStyle为true的弹窗,即弹窗的内容样式完全按照contentNode自定义样式显示。 20 21 ```ts 22 this.ctx.getPromptAction().openCustomDialog(this.contentNode, this.options) 23 .then(() => { 24 console.info('OpenCustomDialog complete.') 25 }) 26 .catch((error: BusinessError) => { 27 let message = (error as BusinessError).message; 28 let code = (error as BusinessError).code; 29 console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`); 30 }) 31 ``` 32 333. 关闭自定义弹窗。 34 35 由于closeCustomDialog接口需要传入待关闭弹窗对应的ComponentContent。因此,如果需要在弹窗中设置关闭方法,则可参考完整示例封装静态方法来实现。 36 37 关闭弹窗之后若需要释放对应的ComponentContent,则需要调用ComponentContent的dispose方法。 38 39 ```ts 40 this.ctx.getPromptAction().closeCustomDialog(this.contentNode) 41 .then(() => { 42 console.info('CloseCustomDialog complete.') 43 }) 44 .catch((error: BusinessError) => { 45 let message = (error as BusinessError).message; 46 let code = (error as BusinessError).code; 47 console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`); 48 }) 49 ``` 50 51## 更新自定义弹窗的内容 52 53ComponentContent与[BuilderNode](../reference/apis-arkui/js-apis-arkui-builderNode.md)有相同的使用限制,不支持自定义组件使用[@Reusable](../quick-start/arkts-create-custom-components.md#自定义组件的基本结构)、[@Link](../quick-start/arkts-link.md)、[@Provide](../quick-start/arkts-provide-and-consume.md)、[@Consume](../quick-start/arkts-provide-and-consume.md)等装饰器,来同步弹窗弹出的页面与ComponentContent中自定义组件的状态。因此,若需要更新弹窗中自定义组件的内容可以通过ComponentContent提供的update方法来实现。 54```ts 55this.contentNode.update(new Params('update')) 56``` 57 58## 更新自定义弹窗的属性 59 60通过updateCustomDialog可以动态更新弹窗的属性。目前支持的属性包括alignment、offset、autoCancel、maskColor。 61需要注意的是,更新属性时,未设置的属性会恢复为默认值。例如,初始设置{ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } },更新时设置{ alignment: DialogAlignment.Bottom },则初始设置的offset: { dx: 0, dy: 50 }不会保留,会恢复为默认值。 62```ts 63this.ctx.getPromptAction().updateCustomDialog(this.contentNode, options) 64 .then(() => { 65 console.info('UpdateCustomDialog complete.') 66 }) 67 .catch((error: BusinessError) => { 68 let message = (error as BusinessError).message; 69 let code = (error as BusinessError).code; 70 console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`); 71 }) 72``` 73 74## 完整示例 75 76```ts 77// PromptActionClass.ts 78import { BusinessError } from '@kit.BasicServicesKit'; 79import { ComponentContent, window } from '@kit.ArkUI'; 80import { UIContext } from '@ohos.arkui.UIContext'; 81 82export class PromptActionClass { 83 static ctx: UIContext; 84 static contentNode: ComponentContent<Object>; 85 static options: Object; 86 87 static setContext(context: UIContext) { 88 this.ctx = context; 89 } 90 91 static setContentNode(node: ComponentContent<Object>) { 92 this.contentNode = node; 93 } 94 95 static setOptions(options: Object) { 96 this.options = options; 97 } 98 99 static openDialog() { 100 if (this.contentNode !== null) { 101 this.ctx.getPromptAction().openCustomDialog(this.contentNode, this.options) 102 .then(() => { 103 console.info('OpenCustomDialog complete.') 104 }) 105 .catch((error: BusinessError) => { 106 let message = (error as BusinessError).message; 107 let code = (error as BusinessError).code; 108 console.error(`OpenCustomDialog args error code is ${code}, message is ${message}`); 109 }) 110 } 111 } 112 113 static closeDialog() { 114 if (this.contentNode !== null) { 115 this.ctx.getPromptAction().closeCustomDialog(this.contentNode) 116 .then(() => { 117 console.info('CloseCustomDialog complete.') 118 }) 119 .catch((error: BusinessError) => { 120 let message = (error as BusinessError).message; 121 let code = (error as BusinessError).code; 122 console.error(`CloseCustomDialog args error code is ${code}, message is ${message}`); 123 }) 124 } 125 } 126 127 static updateDialog(options: Object) { 128 if (this.contentNode !== null) { 129 this.ctx.getPromptAction().updateCustomDialog(this.contentNode, options) 130 .then(() => { 131 console.info('UpdateCustomDialog complete.') 132 }) 133 .catch((error: BusinessError) => { 134 let message = (error as BusinessError).message; 135 let code = (error as BusinessError).code; 136 console.error(`UpdateCustomDialog args error code is ${code}, message is ${message}`); 137 }) 138 } 139 } 140} 141``` 142 143```ts 144// Index.ets 145import { ComponentContent } from '@kit.ArkUI'; 146import { PromptActionClass } from './PromptActionClass'; 147 148class Params { 149 text: string = "" 150 151 constructor(text: string) { 152 this.text = text; 153 } 154} 155 156@Builder 157function buildText(params: Params) { 158 Column() { 159 Text(params.text) 160 .fontSize(50) 161 .fontWeight(FontWeight.Bold) 162 .margin({ bottom: 36 }) 163 Button('Close') 164 .onClick(() => { 165 PromptActionClass.closeDialog() 166 }) 167 }.backgroundColor('#FFF0F0F0') 168} 169 170@Entry 171@Component 172struct Index { 173 @State message: string = "hello" 174 private ctx: UIContext = this.getUIContext(); 175 private contentNode: ComponentContent<Object> = 176 new ComponentContent(this.ctx, wrapBuilder(buildText), new Params(this.message)); 177 178 aboutToAppear(): void { 179 PromptActionClass.setContext(this.ctx); 180 PromptActionClass.setContentNode(this.contentNode); 181 PromptActionClass.setOptions({ alignment: DialogAlignment.Top, offset: { dx: 0, dy: 50 } }); 182 } 183 184 build() { 185 Row() { 186 Column() { 187 Button("open dialog and update options") 188 .margin({ top: 50 }) 189 .onClick(() => { 190 PromptActionClass.openDialog() 191 192 setTimeout(() => { 193 PromptActionClass.updateDialog({ 194 alignment: DialogAlignment.Bottom, 195 offset: { dx: 0, dy: -50 } 196 }) 197 }, 1500) 198 }) 199 Button("open dialog and update content") 200 .margin({ top: 50 }) 201 .onClick(() => { 202 PromptActionClass.openDialog() 203 204 setTimeout(() => { 205 this.contentNode.update(new Params('update')) 206 }, 1500) 207 }) 208 } 209 .width('100%') 210 .height('100%') 211 } 212 .height('100%') 213 } 214} 215``` 216