HarmonyOS :自定義彈窗(CustomDialog)的解耦實踐

引言

在鴻蒙開發(fā)中使用 CustomDialogController@CustomDialog 可實現(xiàn)自定義彈窗交互。但 controller 的定義位置卻有很大的限制。

限制如下:

CustomDialogController僅在作為@CustomDialog@Component struct的成員變量,且在@Component struct內(nèi)部定義時賦值才有效

對于 Dialog 的能力封裝我們通常會將其與調(diào)用者頁面解耦,以 Flutter 為例杏节,我們可能會這么封裝:

typedef DialogCallback = Function(String data);

// 隨便一個工具類
abstract class DialogTool {
  
  static void showCustomDialog(
    BuildContext context,
    DialogCallback callback, // 定義回調(diào)
  ) {
    showDialog(
      context: context,
      builder: (context) {
        return Dialog(
          child: YourWidget(), // dialog UI
        );
      },
    ).then(
      (data) => {
        callback(data),
      },
    );
  }
  
}

在工具類提供靜態(tài)方法谤民,調(diào)用方可直接調(diào)用并獲取返回值慎框。

而在 ArkTS 頁面內(nèi)開發(fā)一個自定義彈窗辆影,不可避免的會有一堆冗余代碼需要被嵌在調(diào)用者UI層,下面我來舉個例子:

  • 首先使用 @CustomDialog 定義一個簡單的帶回調(diào)的 Dialog
@CustomDialog
export struct MyCustomDialog {
  private controller: CustomDialogController
  //確定按鈕回調(diào)
  confirmed: (message: string) => void = (_) => {
  }

  build() {
    Column() {
      Text('這是一個自定義彈窗')
      Button('點擊傳遞數(shù)據(jù)給調(diào)用方').onClick(() => {
        this.controller.close()
        this.confirmed('你好黍特,我是彈窗點擊返回的內(nèi)容')
      })
    }
  }
}
  • 調(diào)用者頁面需要定義 CustomDialogController 綁定 MyCustomDialog 來喚起自定義彈窗
@Component
struct HomePage {
  dialogController?: CustomDialogController | null

  private async showDialog(): Promise<string | undefined> {
    let resolveFunc: (value: string | undefined | PromiseLike<string | undefined>) => void = () => {
    }
    const promise = new Promise<string | undefined>(
      (resolve, _) => {
        resolveFunc = resolve
      }
    )
    this.dialogController = new CustomDialogController({
      builder: MyCustomDialog(
        {
          confirmed: (info) => {
            resolveFunc(info)
          },
        }
      )
    })
    this.dialogController?.open()
    return promise
  }

  build() {
    Column(){
      ... 你的UI布局
    }
  }
}

如上蛙讥,頁面內(nèi)冗余代碼主要體現(xiàn)在 showDialog(){} 內(nèi),當(dāng)你的頁面需要具備多種業(yè)務(wù)的自定義彈窗時灭衷,你就需要在同一個頁面定義多個 showDialog() 方法用以顯示不同的彈窗次慢,接收不同的回執(zhí)傳參。

整體的代碼會變得很亂翔曲,結(jié)構(gòu)封裝會失去簡潔性迫像。

如果不能避開限制,怎么做解耦瞳遍?

我們實踐的方案是做一個空白中間層闻妓,用于存放 CustomDialogControllerCustomDialog 的綁定工作(代碼),只給上層UI提供一個 controller 用來控制彈窗開啟掠械、關(guān)閉由缆、以及接收返回值。以此達(dá)到與調(diào)用方淺解耦的目的猾蒂。

  • 已上文中的 MyCustomDialog 為例均唉,新建一個文件 CustomDialogContainer, 代碼如下:
/// 為了將dialog的初始化與與使用dialog的頁面解耦
@Component
export struct CustomDialogContainer {
  @Link @Watch('onDialogToggle') controller: DialogContainerController
  dialogController?: CustomDialogController | null

  onDialogToggle() {
    if (this.controller.isOpen) {
      this.showDialog().then((data) => {
        this.controller.onDialogConfirm(data)
      })
    } else {
      this.dialogController?.close()
    }
  }

  private async showDialog(): Promise<string | undefined> {
    let resolveFunc: (value: string | undefined | PromiseLike<string | undefined>) => void = () => {
    }
    const promise = new Promise<string | undefined>(
      (resolve, _) => {
        resolveFunc = resolve
      }
    )
    this.dialogController = new CustomDialogController({
      builder: MyCustomDialog(
        {
          confirmed: (info) => {
            resolveFunc(info)
          },
        }
      ),
    })
    this.dialogController?.open()
    return promise
  }

  build() {

  }
}

export class DialogContainerController {
  isOpen: boolean = false;
  onDialogConfirm: (value: string | undefined) => void

  constructor(onConfirm: (value: string | undefined) => void) {
    this.onDialogConfirm = onConfirm
  }

  public open() {
    this.isOpen = true
  }

  public close() {
    this.isOpen = false
  }
}

build(){} 可以看出這是一個空白的 Component 組件。

在調(diào)用者頁面我們這樣使用

@Component
export struct HomePage {
  @State dialogController: DialogContainerController = new DialogContainerController(
    (message: string | undefined) => {
      // 這里接收到彈窗內(nèi)確定按鈕點擊返回的數(shù)據(jù)
      if (message != undefined) {
        // 你的業(yè)務(wù)邏輯
      }
    }
  )

  // 如果有多個樣式的彈窗肚菠,定義多個 dialogController 然后統(tǒng)一在這里管理
  @Builder
  DialogControllerBuilder() {
    Column() {
      CustomDialogContainer({
        controller: this.dialogController
      })
    }
  }

  build() {
    Column() {
      this.DialogControllerBuilder()
      ... 你的UI
    }
  }
}

調(diào)用者業(yè)務(wù)只持有自定義彈窗的 controller 處理交互舔箭,如果有多個自定義彈窗,則定義多個 controller 蚊逢,統(tǒng)一存放管理层扶,在一定程度內(nèi)減少了獨立業(yè)務(wù)的代碼冗余。

附注(Example)

Demo示例(基于API11開發(fā)时捌,支持NEXT及以上版本運行)已上傳可供參考怒医,包含如下內(nèi)容:

  • 靜態(tài)庫+多模塊設(shè)計
  • 狀態(tài)管理+統(tǒng)一路由管理
  • 網(wǎng)絡(luò)請求、Loading奢讨、Log(支持長文本打又商尽) 等工具庫封裝
  • 自定義組件焰薄、自定義彈窗(解耦)
  • EventBus 事件通知
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扒袖,隨后出現(xiàn)的幾起案子塞茅,更是在濱河造成了極大的恐慌,老刑警劉巖季率,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件野瘦,死亡現(xiàn)場離奇詭異,居然都是意外死亡飒泻,警方通過查閱死者的電腦和手機(jī)鞭光,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泞遗,“玉大人惰许,你說我怎么就攤上這事∈氛蓿” “怎么了汹买?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長聊倔。 經(jīng)常有香客問我晦毙,道長,這世上最難降的妖魔是什么耙蔑? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任见妒,我火速辦了婚禮,結(jié)果婚禮上甸陌,老公的妹妹穿的比我還像新娘徐鹤。我一直安慰自己,他們只是感情好邀层,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布返敬。 她就那樣靜靜地躺著,像睡著了一般寥院。 火紅的嫁衣襯著肌膚如雪劲赠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天秸谢,我揣著相機(jī)與錄音凛澎,去河邊找鬼。 笑死估蹄,一個胖子當(dāng)著我的面吹牛塑煎,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播臭蚁,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼最铁,長吁一口氣:“原來是場噩夢啊……” “哼讯赏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起冷尉,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤漱挎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后雀哨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磕谅,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年雾棺,在試婚紗的時候發(fā)現(xiàn)自己被綠了膊夹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡捌浩,死狀恐怖割疾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘉栓,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布拓诸,位于F島的核電站侵佃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏奠支。R本人自食惡果不足惜馋辈,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望倍谜。 院中可真熱鬧迈螟,春花似錦、人聲如沸尔崔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽季春。三九已至洗搂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間载弄,已是汗流浹背耘拇。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留宇攻,地道東北人惫叛。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像逞刷,于是被迫代替她去往敵國和親嘉涌。 傳聞我的和親對象是個殘疾皇子妻熊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容