OpenHarmony—Ets自定义弹窗UI组件封装

系统 OpenHarmony
​ 鸿蒙已经提供了全局UI方法自定义弹窗,本文是基于基础的自定义弹窗来实现提示消息弹窗、确认弹窗、输入弹窗的UI组件封装。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

前言

鸿蒙已经提供了全局UI方法自定义弹窗,本文是基于基础的自定义弹窗来实现提示消息弹窗、确认弹窗、输入弹窗的UI组件封装。

一、消息确认弹窗

首先看下效果:

1、首先先定义一个新的组件ConfirmDialog

@CustomDialog
export default struct ConfirmDialog {
    title: string = ''
    content: string = ''
    confirmFontColor: string = '#E84026'
    cancelFontColor:string = '#0A59F7'
    confirmText:string = '确认'
    cancelText:string = '取消'
    controller: CustomDialogController
    cancel: () => void
    confirm: () => void
    build(){}   
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

自定义确认弹窗可自定义传入的参数有:

可选参数:标题title(默认值:“”),正文内容content(默认值:“”),确认按钮字体颜色confirmFontColor(默认值:#E84026),取消按钮字体颜色cancelFontColor(默认值:#0A59F7),确认按钮文案(默认值:确认),取消按钮文案(默认值:取消)。

必须参数:自定义弹窗控制器controller: CustomDialogController,确认按钮触发事件confirm(),取消按钮触发事件cancel()。

2、标题、正文、按钮封装

一个确认弹窗组件主要由标题、正文等文本内容和取消、确认等按钮事件组成。下面将分别对文案和按钮通过**@Extend**装饰器进行封装。

@Extend装饰器将新的属性函数添加到内置组件上,如Text、Column、Button等。通过**@Extend**装饰器可以快速定义并复用组件的自定义样式。

// 标题title与正文content自定义样式
@Extend(Text) function fancfontSize(fontSize: number) {
  .fontSize(fontSize)
  .width('100%')
  .fontColor('rgba(0, 0, 0, 0.86)')
  .textAlign(TextAlign.Center)
  .padding({ top: 15, bottom: 0, left: 8, right: 8 })
  .alignSelf(ItemAlign.Center)
  .margin({top: 16})
}
// 取消、确认按钮自定义样式
@Extend(Text) function fancBtn(fontColor: string) {
  .fontColor(fontColor)
  .backgroundColor(0xffffff)
  .width(188)
  .height(29)
  .fontSize(22)
  .textAlign(TextAlign.Center)
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

本示例仅标题与正文仅支持字体大小fontSize自定义,按钮仅支持按钮文案字体颜色fontColor自定义,其他通用属性皆是写定的,若想支持其他属性自定义,也可通过fancfontSize()添加新的参数。

其次,可以更进一步的对标题与正文通过@Builder装饰器进行封装,且通过是否传入title、content字段来判断是否展示对应文案。

@Builder装饰的方法用于定义组件的声明式UI描述,在 一个自定义组件内快速生成多个布局内容。 @Builder装饰方法的功能和语法规范与build函数相同。

// 文案样式
  @Builder TipTextStyle(tip:string, fontSize:number) {
    Text(tip)
      .fancfontSize(fontSize)
      .visibility(tip.length > 0 ? Visibility.Visible : Visibility.None)
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

注意:

  1. @Extend装饰器的内容必须写在ConfirmDialog{}组件外,且在@Extend装饰器声明的基础内置组件的 方法之前不能出现用/*多行注释(会报错),但可采用单行注释//。
  2. @Builder装饰器的内容要写在ConfirmDialog{}组件内,build(){}外 。
  3. @Builder装饰器声明的自定义组件内部可包含@Extend声明的自定义样式的基础组件,但是@Extend内部不可包含@Builder装饰器声明的自定义组件。

3、ConfirmDialog组件完整代码

// 取消、确认按钮自定义样式
@Extend(Text) function fancBtn(fontColor: string) {
  .fontColor(fontColor)
  .backgroundColor(0xffffff)
  .width(188)
  .height(29)
  .fontSize(22)
  .textAlign(TextAlign.Center)
}
// 标题title与正文content自定义样式
@Extend(Text) function fancfontSize(fontSize: number) {
  .fontSize(fontSize)
  .width('100%')
  .fontColor('rgba(0, 0, 0, 0.86)')
  .textAlign(TextAlign.Center)
  .padding({ top: 15, bottom: 0, left: 8, right: 8 })
  .alignSelf(ItemAlign.Center)
  .margin({top: 16})
}
@CustomDialog
export default struct ConfirmDialog {
  title: string = ''
  content: string = ''
  confirmFontColor: string = '#E84026'
  cancelFontColor:string = '#0A59F7'
  confirmText:string = '确认'
  cancelText:string = '取消'
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void
  // 标题、正文文案样式
  @Builder TipTextStyle(tip:string, fontSize:number) {
    Text(tip)
      .fancfontSize(fontSize)
      .visibility(tip.length > 0 ? Visibility.Visible : Visibility.None)
  }
  build() {
    Column() {
      this.TipTextStyle(this.title, 28)
      this.TipTextStyle(this.content, 22)
      Flex({ justifyContent: FlexAlign.SpaceAround }) {
        Text(this.cancelText)
          .fancBtn(this.cancelFontColor)
          .onClick(() => {
          this.controller.close()
          this.cancel()
        })
        Text(this.confirmText)
          .fancBtn(this.confirmFontColor)
          .onClick(() => {
            this.controller.close()
            this.confirm()
          })
      }.margin({ top: 30, bottom: 16, left: 16, right: 16 })
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.

4、引用页面代码

import ConfirmDialog from './components/dialog/ConfirmDialog.ets'
@Entry
@Component
struct IndexComponent {
    // 确认弹窗
    private title: string = '标题'
    private content: string = '此操作将永久删除该文件, 是否继续?'
    private confirmText: string = '删除'
    ConfirmDialogController: CustomDialogController = new CustomDialogController({
        builder: ConfirmDialog({ cancel: this.onCancel, confirm: () => {
            this.onAccept()
        },title:this.title, content: this.content}),
        cancel: this.onCancel,
        autoCancel: true
    })
    // 点击取消按钮或遮罩层关闭弹窗
    onCancel() {
        console.info('取消,关闭弹窗')
    }
    // 点击确认弹窗
    onAccept() {
        console.info('确认,关闭弹窗')
    }
    build() {
        Scroll() {
            Column() {
                Text('确认弹窗')
                    .fontSize(24)
                    .width(300)
                    .height(60)
                    .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Solid })
                    .margin({top: 20, bottom:10})
                    .textAlign(TextAlign.Center)
                    .onClick(() => {
                        this.ConfirmDialogController.open()
                    })
            }
            .width('100%')
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.

二、消息提示弹窗

首先看下效果:

1、首先先定义一个新的组件PromptDialog

@CustomDialog
export default struct PromptDialog {
    controller: CustomDialogController
    ancel: () => void
    build() {}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

至于标题、正文、按钮文案及按钮颜色的封装均与消息确认弹窗一样,同1.2所述。

2、PromptDialog组件完整代码

// 标题title与正文content自定义样式
@Extend(Text) function fancfontSize(fontSize: number) {
  .fontSize(fontSize)
  .width('100%')
  .fontColor('rgba(0, 0, 0, 0.86)')
  .textAlign(TextAlign.Center)
  .padding({ top: 15, bottom: 0, left: 8, right: 8 })
  .alignSelf(ItemAlign.Center)
  .margin({top: 16})
}
// 底部按钮自定义样式
@Extend(Text) function fancBtn(fontColor: string) {
  .backgroundColor(0xffffff)
  .fontColor(fontColor)
  .width(188)
  .height(29)
  .fontSize(22)
  .textAlign(TextAlign.Center)
}
@CustomDialog
export default struct PromptDialog {
  controller: CustomDialogController
  cancel: () => void
// 标题、正文文案样式
  @Builder TipTextStyle(tip:string, fontSize:number) {
    Text(tip)
      .fancfontSize(fontSize)
      .visibility(tip.length > 0 ? Visibility.Visible : Visibility.None)
  }
  build() {
    Column() {
      this.TipTextStyle($s('strings.title'), 28)
      this.TipTextStyle($s('strings.content'), 22)
      Flex({ justifyContent: FlexAlign.Center }) {
        Text($s('strings.confirm'))
          .fancBtn(0x0A59F7)
          .onClick(() => {
            this.controller.close()
          })
      }.margin({ top: 30, bottom: 16 })
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.

若标题title与正文content中的文案是固定的,可如此示例一样,可采用写入到resource中的zh_CN和en_US文件中,通过$s(‘strings.title’)取值显示,若是动态获取的,可采用消息确认弹窗中传参方式。

3、引用页面代码

import PromptDialog from './components/dialog/PromptDialog.ets'
@Entry
@Component
struct IndexComponent {
    // 消息提示弹窗
    PromptDialogController: CustomDialogController = new CustomDialogController({
        builder: PromptDialog(),
        autoCancel: true
    })
    build() {
        Scroll() {
            Column() {
                Text('消息提示弹窗')
                    .fontSize(24)
                    .width(300)
                    .height(60)
                    .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Solid })
                    .margin({top: 20, bottom:10})
                    .textAlign(TextAlign.Center)
                    .onClick(() => {
                        this.PromptDialogController.open()
                    })
            }
            .width('100%')
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

三、消息输入弹窗

首先看下效果:

1、首先先定义一个新的组件InputDialog

export default struct InputDialog {
  title: string = ''
  content: string = ''
  @State inputString:string = ''
  controller: CustomDialogController
  cancel: () => void
  confirm: (data) => void
  build() {}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

此示例讲述了子组件通过事件触发传参给父组件的方法,例如:在子组件用@state声明输入框内容inputString,通过confirm事件传参给父组件,可支持在父组件至于标题、正文、按钮文案及按钮颜色的封装均与消息确认弹窗一样,同1.2所述。

2、PromptDialog组件完整代码

// 取消、确认按钮自定义样式
@Extend(Text) function fancBtn(fontColor: string) {
  .fontColor(fontColor)
  .backgroundColor(0xffffff)
  .width(188)
  .height(29)
  .fontSize(22)
  .textAlign(TextAlign.Center)
}
// 标题title与正文content自定义样式
@Extend(Text) function fancfontSize(fontSize: number) {
  .fontSize(fontSize)
  .width('100%')
  .fontColor('rgba(0, 0, 0, 0.86)')
  .textAlign(TextAlign.Start)
  .padding({ top: 15, bottom: 0, left: 15, right: 15 })
  .margin({top: 16})
}
@CustomDialog
export default struct InputDialog {
  title: string = ''
  content: string = ''
  @State inputString:string = ''
  controller: CustomDialogController
  cancel: () => void
  confirm: (data) => void
  // 文案样式
  @Builder TipTextStyle(tip:string, fontSize:number) {
    Text(tip)
      .fancfontSize(fontSize)
      .visibility(tip.length > 0 ? Visibility.Visible : Visibility.None)
  }
  build() {
    Column() {
      this.TipTextStyle(this.title, 28)
      this.TipTextStyle(this.content, 22)
      // 输入框
      TextInput()
        .type(InputType.Normal)
        .enterKeyType(EnterKeyType.Next)
        .caretColor(Color.Green)
        .height(44)
        .margin({top: 20, left: 15; right:15})
        .alignSelf(ItemAlign.Center)
        .onChange((value: string) => {
          this.inputString = value
        })
      Flex({ justifyContent: FlexAlign.SpaceAround }) {
        Text($s('strings.cancel'))
          .fancBtn('#0A59F7')
          .onClick(() => {
          this.controller.close()
          this.cancel()
        })
        Text($s('strings.confirm'))
          .fancBtn('#E84026')
          .onClick(() => {
            this.controller.close()
            console.log('inputString:'+this.inputString)
            this.confirm(this.inputString)
          })
      }.margin({ top: 30, bottom: 16, left: 16, right: 16 })
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.

3、引用页面代码

import InputDialog from './components/dialog/InputDialog.ets'
@Entry
@Component
struct IndexComponent {
// 输入弹窗
    private text: string = '提示'
    private label: string = '请输入您的姓名'
    InputDialogController: CustomDialogController = new CustomDialogController({
        builder: InputDialog({ cancel: this.onCancel, confirm: (data) => {
            this.confirm(data)
        },title: this.text, content: this.label }),
        cancel: this.onCancel,
        autoCancel: true
    })
// 点击取消按钮或遮罩层关闭弹窗
    onCancel() {
        console.info('取消,关闭输入弹窗')
    }
// 点击确认弹窗
    confirm(data) {
        console.info('确认,关闭输入弹窗,data:'+data)
    }
    build() {
        Scroll() {
            Column() {
                Text('输入弹窗')
                    .fontSize(24)
                    .width(300)
                    .height(60)
                    .border({ width: 5, color: 0x317AF7, radius: 10, style: BorderStyle.Solid })
                    .margin({top: 20, bottom:10})
                    .textAlign(TextAlign.Center)
                    .onClick(() => {
                        this.InputDialogController.open()
                    })
            }
            .width('100%')
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

本文仅仅实现了三种自定义弹窗UI组件的封装(传参方式也讲解了多种,具体传参方式可视具体情况而定)。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://ost.51cto.com​

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2022-05-26 14:50:15

ArkUITS扩展

2022-09-16 15:34:32

CanvasArkUI

2022-04-24 14:56:53

容器组件StackTS

2023-08-10 17:14:52

鸿蒙自定义弹窗

2022-06-30 14:02:07

鸿蒙开发消息弹窗组件

2022-03-01 16:09:06

OpenHarmon鸿蒙单选组件

2009-06-25 14:53:35

自定义UI组件JSF框架

2021-09-15 10:19:15

鸿蒙HarmonyOS应用

2022-10-17 14:39:12

自定义弹窗组件鸿蒙

2022-10-10 14:51:51

ArkUI eTSPieChart组件

2022-10-09 15:13:18

TextPickerArkUI eTS

2021-11-22 10:00:33

鸿蒙HarmonyOS应用

2022-04-07 14:17:15

Harmonytoast组件鸿蒙

2022-07-15 16:39:46

ETS导航栏组件

2022-02-21 15:05:09

LauncherOpenHarmon鸿蒙

2022-04-24 15:17:56

鸿蒙操作系统

2022-04-11 11:07:37

HarmonyUI小型系统textarea

2021-11-01 10:21:36

鸿蒙HarmonyOS应用

2009-06-24 15:13:36

自定义JSF组件

2023-02-20 15:20:43

启动页组件鸿蒙
点赞
收藏

51CTO技术栈公众号