美文网首页
【鸿蒙开发细枝末节】自定义弹窗实现

【鸿蒙开发细枝末节】自定义弹窗实现

作者: 天枢破军 | 来源:发表于2024-03-24 02:50 被阅读0次

    前言

    鸿蒙官方的文档写得很详细,也有Demo示例代码,但从《构建更加丰富的界面》这个章节起,大段大段地省略重要内容,包括但不限于“在代码片段里写一大堆省略号”、“只贴代码片段不说贴在什么位置”、“对另一个先前教学中没有提到过的内容只字不提或一笔带过”等情况,导致学习时不得不去翻文档看Demo自己试错。而Demo也做得非常复杂,根本不适合初学者阅读。
    这个《细枝末节》系列算是作为官方教学的补充,给初学者看的,专门补充官方教学文档没说的细节。

    本文是对《构建更加丰富的页面》中《自定义窗口》部分的补充

    本文对应的API版本是9
    开发工具版本
    DevEco Studio 3.1.1 Release
    Build Version: 3.1.0.501, built on June 20, 2023
    Build #DS-223.8617.56.36.310501
    Runtime version: 17.0.6+10-b829.5 amd64
    VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
    Windows 10 10.0
    GC: G1 Young Generation, G1 Old Generation
    Memory: 1024M
    Cores: 16
    Registry:
    external.system.auto.import.disabled=true

    Non-Bundled Plugins:
    com.intellij.marketplace (223.8617.59)
    izhangzhihao.rainbow.brackets (2023.3.7)

    实现效果

    原文的自定义窗口写得非常复杂,甚至用到了先前教程未提及的数据部分。

    本文直接换用一个简单的例子。我们来实现第一部分《管理组件状态》那个界面下面的“添加子目标”弹窗。

    效果.PNG

    编写自定义弹窗类

    创建一个新文件,我这里起名叫OkCancelInputDialog

    然后声明如下:

    @CustomDialog
    export default struct OkCancelInputDialog {
      
      build() {
        
      }
    }
    

    @CustomDialog这个注解表示这个控件是对话框
    export default如果不写这个的话,无法被其他文件调用

    接下来我们在build里面写界面,先分析一下效果图:
    一个输入框TextInput,两个按钮Button水平排列,输入框和按钮竖直排列。
    最外层使用Column排列输入框和按钮,两个按钮使用Row包起来横排,按钮中间用Blank填充空隙。

    补全界面代码如下:

    build() {
      Column() {
        TextInput({ placeholder: '请输入内容' }) //输入框
          .onChange((str) => {
            //TODO:更新输入内容
          })
          .margin({ left: 16, right: 16 })
    
        Row() {
          Button("取消", { type: ButtonType.Capsule })
            .onClick(() => {
              //TODO:点击取消按钮的事件
            })
            .backgroundColor(Color.White)
            .fontColor(Color.Blue)
            .width("45%")
    
          Blank()
    
          Button("确定", { type: ButtonType.Capsule })
            .onClick(() => {
              //TODO:点击确定按钮的事件
            })
            .backgroundColor(Color.Blue)
            .fontColor(Color.White)
            .width("45%")
        }
        .width('100%')
        .margin({ top: 16, bottom: 16, left: 32, right: 32 })
      }
      .margin({ left: 16, right: 16 })
      .padding({ top: 24, bottom: 24 })
    }
    

    然后再创建一个变量来保存输入的值,创建两个方法对应两个按钮的点击事件。最终这个类的代码如下:

    @CustomDialog
    export default struct OkCancelInputDialog {
      inputValue: string//存放输入内容的变量
      controller: CustomDialogController
      cancel: () => void//取消按钮对应事件
      confirm: (string) => void//确定按钮对应事件
    
      build() {
        Column() {
          TextInput({ placeholder: '请输入内容' }) //输入框
            .onChange((str) => {
              this.inputValue = str
            })
            .margin({ left: 16, right: 16 })
    
          Row() {
            Button("取消", { type: ButtonType.Capsule })
              .onClick(() => {
                this.cancel();
              })
              .backgroundColor(Color.White)
              .fontColor(Color.Blue)
              .width("45%")
    
            Blank()
    
            Button("确定", { type: ButtonType.Capsule })
              .onClick(() => {
                this.confirm(this.inputValue);
              })
              .backgroundColor(Color.Blue)
              .fontColor(Color.White)
              .width("45%")
          }
          .width('100%')
          .margin({ top: 16, bottom: 16, left: 32, right: 32 })
        }
        .margin({ left: 16, right: 16 })
        .padding({ top: 24, bottom: 24 })
      }
    }
    

    调用弹窗

    来到要调用弹窗的界面,在文件头import自定义弹窗类,然后声明一个CustomDialogController
    (这个写法我是照着Demo抄的,我目前还不知道Controller到底是什么,只知道这玩意可以操作自定义弹窗对象。猜测是类似于 Android 的 Service 和 Binder 的关系。)

    import OkCancelInputDialog from './OkCancelInputDialog';
    
    @Entry
    @Component
    struct Index {
    
      dialogController: CustomDialogController = new CustomDialogController({
        builder: OkCancelInputDialog({
          confirm: (str): void => this.onAccept(str),
          cancel: (): void => this.onCancel(),
        })
      });
    
      build() {
        Column() {
          //点击显示弹窗
          Button('点击添加', { type: ButtonType.Capsule, stateEffect: true })
            .borderRadius(8)
            .backgroundColor("#ff0078d2")
            .onClick(() => {
              if (this.dialogController != undefined) {
                this.dialogController.open()//显示弹窗
              }
            })
            .fontSize(20)
            .padding({ left: 32, right: 32, top: 16, bottom: 16 })
            .margin({ bottom: 32 })
        }
        .width('100%')
        .height('100%')
        .backgroundColor("#ffe0e0e0")
      }
    
      onAccept(str) {
        console.log(str); //打印输入的值
        this.dialogController.close();//关闭弹窗
      }
    
      onCancel() {
        this.dialogController.close();//关闭弹窗
      }
    
    }
    

    这里的confirmcancel是自定义弹窗类中定义的函数名,在自定义弹窗类中,括号里的 string 是参数的类型。此处调用的地方,括号里的 str 是参数的名字。有点类似于 Android 的 Listener 的写法。

    注意这里不能这样写

    cancel:this.oncancel//编译能过,但会报运行时异常。
    或者
    cancel:this.oncancel()//编译能过,但会报运行时异常。
    

    也可以不引用一个函数,而是直接写函数体

    cancel: (): void => this.dialogController.close()//关闭弹窗
    

    相关文章

      网友评论

          本文标题:【鸿蒙开发细枝末节】自定义弹窗实现

          本文链接:https://www.haomeiwen.com/subject/hvtltjtx.html