一、簡介

ArkUI的彈出框控制器在綁定彈出框後,可提供對彈出框的操作能力,當前支持關閉功能。可以將控制器傳入彈出框內容區域後進行操作。
API version 18開始,可設置controller參數以綁定DialogController控制器,通過控制器能夠操作彈出框。

二、使用約束

目前openCustomDialogWithController和presentCustomDialog支持通過controller參數來綁定彈出框進行操作,目前getDialogController支持獲取自定義組件所在的彈出框的控制器。

説明 一個彈出框控制器只能綁定一個彈出框,且操作只對該彈出框生效。 使用getDialogController獲取彈出框控制器時,如果當前自定義組件不在彈出框中顯示則獲取為undefined。

三、創建自定義內容為ComponentContent的彈出框控制器

  1. 初始化一個自定義彈出框內容區的入參類,內部包含彈出框控制器。
class Params {
  public text: string = ''
  public dialogController: promptAction.CommonController = new promptAction.DialogController()
  constructor(text: string, dialogController: promptAction.CommonController) {
    this.text = text
    this.dialogController = dialogController
  }
}
  1. 初始化一個自定義的彈出框內容區,內部包含一個按鈕,該按鈕通過該自定義組件自帶的彈出框控制器實現關閉功能。
@Component
struct MyComponent {
  build() {
    Column({ space: 5 }) {
      Button('點我關閉彈窗:通過自定義組件自帶的DialogController')
        .onClick(() => {
          let dialogController: promptAction.DialogController = this.getDialogController()
          if (dialogController !== undefined) {
            dialogController.close()
          }
        })
    }
  }
}
  1. 初始化另一自定義彈出框內容區,其中包含一個Text組件和一個按鈕,該按鈕通過外部傳遞的彈出框控制器用於關閉彈出框,並且該內容區還包含前一個自定義彈出框內容區。
@Builder
function buildText(params: Params) {
  Column({ space: 5 }) {
    Text(params.text)
      .fontSize(30)
    if (params.dialogController !== undefined) {
      Button('點我關閉彈窗:通過外部傳遞的DialogController')
        .onClick(() => {
          params.dialogController.close()
        })
    }
    MyComponent()
  }
  .width(300)
  .height(200)
  .backgroundColor('#FFF0F0F0')
}
  1. 初始化一個彈出框控制器,並通過設置控制器參數來初始化一個彈出框內容實體對象。最後,通過調用UIContext中的getPromptAction方法獲取PromptAction對象,再通過該對象調用openCustomDialogWithController接口,並且設置初始化的內容實體對象和控制器參數以創建彈出框。
let dialogController: promptAction.CommonController = new promptAction.DialogController()
let contentNode: ComponentContent<Object> =
  new ComponentContent(this.getUIContext(), wrapBuilder(buildText), new Params(this.message, dialogController))
this.getUIContext().getPromptAction().openCustomDialogWithController(
  contentNode, dialogController, this.baseDialogOptions).catch((err: BusinessError) => {
  console.error('openCustomDialogWithController error: ' + err.code + ' ' + err.message)
})

四、創建自定義內容為CustomBuilder的彈出框控制器

  1. 初始化一個自定義彈出框內容區,內部包含一個Text組件和一個按鈕,該按鈕通過外部傳遞的彈出框控制器實現關閉功能。
@Builder customDialogComponent(dialogController: promptAction.DialogController) {
  Column({ space: 5 }) {
    Text(this.message)
      .fontSize(30)
    if (dialogController !== undefined) {
      Button('點擊關閉彈窗:通過外部傳遞的DialogController')
        .onClick(() => {
          dialogController.close()
        })
    }
  }
  .height(200)
  .padding(5)
  .justifyContent(FlexAlign.SpaceBetween)
  .backgroundColor('#FFF0F0F0')
}
  1. 初始化一個彈出框控制器,並通過調用UIContext中的getPromptAction方法獲取PromptAction對象,再通過該對象調用presentCustomDialog接口,設置初始化的內容實體對象和控制器參數以創建彈出框。
let dialogController: promptAction.CommonController = new promptAction.DialogController()
this.getUIContext().getPromptAction().presentCustomDialog(() => {
  this.customDialogComponent(dialogController)
}, dialogController, this.dialogOptions).catch((err: BusinessError) => {
  console.error('presentCustomDialog error: ' + err.code + ' ' + err.message)
})

五、在CustomDialogController內容區直接獲取彈出框控制器

  1. 初始化一個自定義彈出框內容區,內部包含一個Text組件和一個按鈕,該按鈕通過彈出框控制器關閉彈出框。
@CustomDialog
@Component
struct CustomDialogExample {
  controller?: CustomDialogController

  build() {
    Column({ space: 5 }) {
      Text('我是內容')
        .fontSize(30)
      Button('點我關閉彈窗:通過自定義組件自帶的DialogController')
        .onClick(() => {
          let dialogController: PromptActionDialogController = this.getDialogController()
          if (dialogController !== undefined) {
            dialogController.close()
          }
        })
    }
    .height(200)
    .backgroundColor('#FFF0F0F0')
  }
}
  1. 初始化一個自定義彈出框構造器,關聯自定義彈出框內容區。
let customDialogController: CustomDialogController = new CustomDialogController({
  builder: CustomDialogExample(),
})
customDialogController.open()

六、使用控制器獲取彈出框的狀態

在自定義彈出框場景中,可以通過控制器調用getState接口獲取彈出框狀態。
初始化一個自定義彈出框內容區,內部包含一個Text組件和一個按鈕,該按鈕通過調用getState獲取當前彈出框狀態。

@Builder customDialogComponent(dialogController: promptAction.DialogController) {
  Column({ space: 5 }) {
    Text(this.message)
      .fontSize(30)
    if (dialogController !== undefined) {
      Button('點我查詢彈窗狀態')
        .onClick(() => {
          console.info('state:' + this.dialogController.getState())
        })
    }
  }
  .height(200)
  .padding(5)
  .justifyContent(FlexAlign.SpaceBetween)
  .backgroundColor('#FFF0F0F0')
}

七、完整示例

通過外部傳遞的彈出框控制器和自定義組件自帶的彈出框控制器,在自定義彈出框內容區域內實現關閉功能。

效果圖

HarmonyOS:彈出框控制器_鴻蒙

import { ComponentContent, promptAction } from '@kit.ArkUI'
import { BusinessError } from '@kit.BasicServicesKit'

class Params {
  public text: string = ''
  public dialogController: promptAction.CommonController = new promptAction.DialogController()

  constructor(text: string, dialogController: promptAction.CommonController) {
    this.text = text
    this.dialogController = dialogController
  }
}

@Component
struct MyComponent {
  build() {
    Column({ space: 5 }) {
      Button('點我關閉彈窗:通過自定義組件自帶的DialogController')
        .onClick(() => {
          let dialogController: promptAction.DialogController = this.getDialogController() // API version 18
          if (dialogController !== undefined) {
            dialogController.close()
          }
        })
    }
  }
}

@Builder
function buildText(params: Params) {
  Column({ space: 5 }) {
    Text(params.text)
      .fontSize(30)
    if (params.dialogController !== undefined) {
      Button('點我關閉彈窗:通過外部傳遞的DialogController')
        .onClick(() => {
          params.dialogController.close()
        })
    }
    MyComponent()
  }
  .width(300)
  .height(200)
  .backgroundColor('#FFF0F0F0')
}

@CustomDialog
@Component
struct CustomDialogExample {
  controller?: CustomDialogController

  build() {
    Column({ space: 5 }) {
      Text('我是內容')
        .fontSize(30)
      Button('點我關閉彈窗:通過自定義組件自帶的DialogController')
        .onClick(() => {
          let dialogController: PromptActionDialogController = this.getDialogController()
          if (dialogController !== undefined) {
            dialogController.close()
          }
        })
    }
    .height(200)
    .backgroundColor('#FFF0F0F0')
  }
}

@Entry
@Component
export struct TestOpenCustomDialog5 {
  private message = '彈窗'

  @Builder
  customDialogComponent(dialogController: promptAction.DialogController) {
    Column({ space: 5 }) {
      Text(this.message)
        .fontSize(30)
      if (dialogController !== undefined) {
        Button('點擊關閉彈窗:通過外部傳遞的DialogController')
          .onClick(() => {
            dialogController.close()
          })
      }
    }
    .height(200)
    .padding(5)
    .justifyContent(FlexAlign.SpaceBetween)
    .backgroundColor('#FFF0F0F0')
  }

  @Builder
  customDialogComponentWithId(dialogId: number, dialogController: promptAction.DialogController) {
    Column({ space: 5 }) {
      Text(this.message)
        .fontSize(30)
      if (dialogId !== undefined) {
        Button('點擊關閉彈窗:通過DialogID')
          .onClick(() => {
            this.getUIContext().getPromptAction().closeCustomDialog(dialogId)
          })
      }
      if (dialogController !== undefined) {
        Button('點擊關閉彈窗:通過外部傳遞的DialogController')
          .onClick(() => {
            dialogController.close()
          })
      }
    }
  }

  private baseDialogOptions: promptAction.BaseDialogOptions = {
    isModal: false,
    autoCancel: false
  }
  private dialogOptions: promptAction.DialogOptions = {
    isModal: false,
    autoCancel: false
  }

  openCustomDialogWithController() {
    let dialogController: promptAction.CommonController = new promptAction.DialogController()
    let contentNode: ComponentContent<Object> =
      new ComponentContent(this.getUIContext(), wrapBuilder(buildText),
        new Params(this.message, dialogController))
    this.getUIContext().getPromptAction().openCustomDialogWithController(
      contentNode, dialogController, this.baseDialogOptions).catch((err: BusinessError) => {
      console.error('openCustomDialogWithController error: ' + err.code + ' ' + err.message)
    })
  }

  presentCustomDialogWithCustomBuilder() {
    let dialogController: promptAction.CommonController = new promptAction.DialogController()
    this.getUIContext().getPromptAction().presentCustomDialog(() => {
      this.customDialogComponent(dialogController)
    }, dialogController, this.dialogOptions).catch((err: BusinessError) => {
      console.error('presentCustomDialog error: ' + err.code + ' ' + err.message)
    })
  }

  presentCustomDialogWithCustomBuilderWithId() {
    let dialogController: promptAction.CommonController = new promptAction.DialogController()
    this.getUIContext().getPromptAction().presentCustomDialog((dialogId: number) => {
      this.customDialogComponentWithId(dialogId, dialogController)
    }, dialogController, this.dialogOptions).catch((err: BusinessError) => {
      console.error('presentCustomDialog error: ' + err.code + ' ' + err.message)
    })
  }

  customDialogController() {
    let customDialogController: CustomDialogController = new CustomDialogController({
      builder: CustomDialogExample(),
    })
    customDialogController.open()
  }

  build() {
    Column({ space: 20 }) {
      Button('openCustomDialogWithController彈窗').margin({top: 40})
        .onClick(() => {
          this.openCustomDialogWithController()
        })
      Button('presentCustomDialog+CustomBuilder彈窗')
        .onClick(() => {
          this.presentCustomDialogWithCustomBuilder()
        })
      Button('presentCustomDialog+CustomBuilderWithId彈窗')
        .onClick(() => {
          this.presentCustomDialogWithCustomBuilderWithId()
        })
      Button('CustomDialogController彈窗')
        .onClick(() => {
          this.customDialogController()
        })
    }.width('100%')
  }
}