• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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