# CustomDialog动态设置宽高

#### 问题现象

如何动态修改弹出框的样式，如宽、高等？

#### 背景知识

*   自定义弹窗CustomDialog通过CustomDialogController类显示自定义弹窗，弹窗在初始化时通过入参CustomDialogControllerOptions配置参数。自定义弹窗的所有参数，不支持动态刷新，如CustomDialogControllerOptions可设置弹窗的宽高等参数，但设置之后不可改变。
*   ComponentContent实现组件内容的实体封装，其对象支持在非UI组件中创建与传递，便于开发者对弹窗类组件进行解耦封装。
*   update：用于更新WrappedBuilder对象封装的builder函数参数，与constructor传入的参数类型保持一致。
*   PromptAction：创建并显示文本提示框、对话框和操作菜单，和当前UI上下文相关联。
*   updateCustomDialog：更新已弹出的dialogContent对应的自定义弹窗的样式，使用Promise异步回调。

#### 解决方案

*   **方案一**：一个CustomDialogController类对应一个CustomDialog弹窗，由于CustomDialogController内部参数不支持动态刷新，可通过创建新的CustomDialogController实例实现动态修改弹窗样式的效果。
    
    ```
    @CustomDialog
    struct CustomDialogExample {
      controller?: CustomDialogController;
    
      build() {
        Column({ space: 24 }) {
          Text('这是自定义弹窗')
            .maxLines(1)
            .textOverflow({ overflow: TextOverflow.Ellipsis })
            .fontSize(16);
          Button('Close')
            .onClick(() => {
              if (this.controller !== undefined) {
                this.controller.close();
              }
            });
        }.padding(24);
      }
    }
    
    @Entry
    @Component
    struct CustomDialogUser {
      dialogController: CustomDialogController | null = null;
    
      aboutToAppear(): void {
        this.createDialogCtl(300); // 创建CustomDialogController对象，宽度300
      }
    
      aboutToDisappear() {
        this.dialogController = null; // 将dialogController置空
      }
    
      // 创建宽度不同的新弹窗
      createDialogCtl(width: number): void {
        this.dialogController = new CustomDialogController({
          builder: CustomDialogExample(),
          autoCancel: true,
          alignment: DialogAlignment.Center,
          offset: { dx: 0, dy: -20 },
          customStyle: false,
          cornerRadius: 20,
          width: width,
          backgroundColor: Color.White,
        });
      }
    
      build() {
        Column({ space: 24 }) {
          Button('click me')
            .onClick(() => {
              if (this.dialogController != null) {
                this.dialogController.open();
              }
            });
          Button('change')
            .onClick(() => {
              this.createDialogCtl(150); // 创建新的CustomDialogController对象，宽度150
            });
        }.width('100%').margin({ top: 16 });
      }
    }
    ```
    
    *   使用限制：实际是创建了新弹窗，所以修改样式后需要先关闭弹窗再重新打开弹窗才有效。
    *   样式修改的范围：CustomDialogControllerOptions对象支持的参数均可修改，如width、maskColor、offset等。
    *   效果如下：点击change按钮后，创建了一个新的弹窗，改变了原弹窗的宽度。
        
*   **方案二**：使用ComponentContent封装弹窗的UI，使用PromptAction控制弹窗的显隐，使用ComponentContent的update方法更新弹窗，实现动态修改弹窗样式的效果。
    
    ```
    import { ComponentContent } from '@kit.ArkUI';
    
    interface ParamsInterface {
      text: string;
    }
    
    @Builder
    function buildText(params: ParamsInterface) {
      Column() {
        Text(params.text)
          .fontSize(24);
      }.padding(24)
      .borderRadius(16)
      .justifyContent(FlexAlign.Center)
      .backgroundColor(Color.White);
    }
    
    @Entry
    @Component
    struct ComponentContentDemo {
      build() {
        Column() {
          Button('click me')
            .onClick(() => {
              let uiContext = this.getUIContext();
              let promptAction = uiContext.getPromptAction();
              // 自定义弹窗的内容
              let contentNode = new ComponentContent<ParamsInterface>(uiContext, wrapBuilder<[ParamsInterface]>(buildText),
                { text: 'old style' });
              promptAction.openCustomDialog(contentNode);
              setTimeout(() => {
                contentNode.update({ text: 'new style' });
              }, 2000); // 2秒后自动更新弹窗内容文本
            });
        }.width('100%').height('100%').margin({ top: 16 });
      }
    }
    ```
    
    *   可以在弹窗展示的过程中动态修改样式，只要update方法支持传递的参数均可用于动态修改样式。
    *   效果如下：在弹窗显示的过程中，更新弹窗的文字。
        
*   **方案三**：和方案二一样使用PromptAction显示弹窗，使用updateCustomDialog更新弹窗样式，但目前仅支持更新alignment、offset、autoCancel、maskColor四种属性。使用方法可参考updateCustomDialog下方的代码示例。

#### 常见FAQ

Q：CustomDialog的offset能不能响应式更新？

A：自定义弹窗(CustomDialog)的所有参数，不支持动态刷新。推荐使用不依赖UI组件的全局自定义弹出框 (openCustomDialog)。

Q：如何让dialog在隐藏的情况下，再展示时，数据不消失？

A：可以将弹窗数据同步保存至父组件中，可以参考使用@Link和@Consume监听数据变化。

Q：如何设置弹窗的位置，使其弹出到屏幕上层？

A：可以修改CustomDialogControllerOptions对象的offset参数，实现改变弹窗的位置。