一、簡介

ArkUI的彈出框默認設置為全局級別,彈窗節點作為頁面根節點的子節點,顯示層級高於應用中的所有路由/導航頁面。當頁面內進行路由跳轉時,如果應用未主動調用close方法關閉彈出框,彈出框不會自動關閉,並且會在下一個跳轉頁面上繼續顯示。
從API version 15開始,如果開發者希望在路由跳轉後,彈出框能夠隨前一個路由頁面的切換而消失,並在路由返回後彈出框能夠繼續正常顯示,可以通過頁面級彈出框來實現。

説明 當且僅當彈出框為非子窗模式時,頁面級能力才會生效。即showInSubWindow參數不設置或設置為false。 頁面級彈出框通常與導航路由能力結合使用,可以參考組件導航和頁面路由概述瞭解相關術語。 頁面級彈出框的使用方式是在當前彈出框的入參之中新增了相關屬性能力,使用前可以通過彈出框概述瞭解基礎的彈出框使用方法。

二、設置頁面級彈出框參數

説明 詳細變量定義請參考下面完整示例。

在彈出框的options入參中設置levelMode屬性,值為LevelMode.EMBEDDED表示開啓頁面級彈出框能力。
當彈出框彈出時,會自動獲取當前顯示的Page頁面並將彈出框節點掛載在此頁面下。此時彈出框的顯示層級高於此Page頁面下的所有Navigation頁面。

this.getUIContext().getPromptAction().openCustomDialog({
  builder: () => {
    this.customDialogComponent();
  },
  levelMode: LevelMode.EMBEDDED, // 啓用頁面級彈出框
})

三、彈出框在指定頁面內彈出

如果希望彈出框顯示在某個指定頁面內,需通過第二個參數levelUniqueId來實現。此參數接收頁面內的節點id,設置後,彈出框顯示時會自動查詢此id對應的節點所在的Navigation頁面,並將其掛載在子頁面的NavDestination節點下。
如下代碼示例所示,Text節點為指定頁面的節點,設置自定義id後,通過getFrameNodeById方法獲取該節點,再通過getUniqueId獲取節點的內部id,並將其作為levelUniqueId的值傳入。

Text(this.message).id("test_text")
  .onClick(() => {
    const node: FrameNode | null = this.getUIContext().getFrameNodeById("test_text") || null;
    this.getUIContext().getPromptAction().openCustomDialog({
      builder: () => {
        this.customDialogComponent();
      },
      levelMode: LevelMode.EMBEDDED, // 啓用頁面級彈出框
      levelUniqueId: node?.getUniqueId(), // 設置頁面級彈出框所在頁面的任意節點ID
    })
  })

四、設置頁面級彈出框蒙層樣式

如果彈出框配置了蒙層,蒙層的遮蓋範圍會根據頁面層級的變化進行調整,默認遮罩範圍為彈出框父節點的顯示區域(Page頁面或者Navigation頁面)。此時,狀態欄和導航條不會被蒙層遮擋。若希望遮擋狀態欄和導航條,可將immersiveMode參數的值設為ImmersiveMode.EXTEND。

Text(this.message).id("test_text")
  .onClick(() => {
    const node: FrameNode | null = this.getUIContext().getFrameNodeById("test_text") || null;
    this.getUIContext().getPromptAction().openCustomDialog({
      builder: () => {
        this.customDialogComponent();
      },
      levelMode: LevelMode.EMBEDDED, // 啓用頁面級彈出框
      levelUniqueId: node?.getUniqueId(), // 設置頁面級彈出框所在頁面的任意節點ID
      immersiveMode: ImmersiveMode.EXTEND, // 設置頁面級彈出框蒙層的顯示模式
    })
  })

五、交互説明

頁面內彈出框在部分交互邏輯上依然遵循部分彈出框指定的交互策略:

  1. 側滑時先關閉彈出框。通過側滑手勢返回上一頁時,如果頁面上存在彈出框,彈出框會優先關閉並結束本次手勢行為。如果期望返回上一頁,需要再次觸發側滑手勢。
  2. 點擊彈出框的蒙層,默認會關閉彈出框,點擊蒙層以外的區域則不會。
效果圖

HarmonyOS:頁面級彈出框_HarmonyOS

示例完整代碼

import { LevelMode, ImmersiveMode } from '@kit.ArkUI'

const TAG = "TestOpenCustomDialog3"
let customDialogId: number = 0;

@Builder
function customDialogBuilder(uiContext: UIContext) {
  Column() {
    Text('這是一個頁面級彈框').fontSize(20).height(100)
    Row() {
      Button("確定").onClick(() => {
        // 在彈窗內部進行路由跳轉。
        uiContext.getRouter().pushUrl({ url: 'pages/dialog/TestOpenCustomDialog' });
      })
      Blank().width(50)
      Button("取消").onClick(() => {
        uiContext.getPromptAction().closeCustomDialog(customDialogId);
      })
    }
  }.padding(20)
}

const BTN_ID = "test_btn"

@Entry
@Component
struct TestOpenCustomDialog3 {
  private uiContext: UIContext = this.getUIContext();

  @Builder
  customDialogComponent() {
    customDialogBuilder(this.uiContext);
  }

  openCustomDialog() {
    const node: FrameNode | null = this.getUIContext().getFrameNodeById(BTN_ID) || null;
    this.uiContext.getPromptAction().openCustomDialog({
      builder: () => {
        this.customDialogComponent();
      },
      levelMode: LevelMode.EMBEDDED, // 啓用頁面級彈出框
      levelUniqueId: node?.getUniqueId(), // 設置頁面級彈出框所在頁面的任意節點ID
      immersiveMode: ImmersiveMode.EXTEND, // 設置頁面級彈出框蒙層的顯示模式
    }).then((dialogId: number) => {
      customDialogId = dialogId;
    })
  }

  build() {
    Column({ space: 10 }) {
      Button("頁面級彈框")
        .id(BTN_ID)
        .fontSize(20)
        .margin({ top: 60 })
        .onClick(() => {
          this.openCustomDialog()
        })
    }
    .height('100%')
    .width('100%')
  }
}