基于ArkUI组件picker的自定义实现

superinsect
发布于 2025-1-22 11:34
浏览
0收藏

场景一:自定义TextPickerDialog

方案:

开发者对于Picker这块常常会有一个误区,在使用Picker这块弹窗的时候优先会使用封装好的PikcerDialog类组件;但是需要注意的是,PikcerDialog类的组件是和系统颜色保持一致的,并不支持自定义;当需要自定义Picker弹窗时,优先考虑自行封装。所以,开发者使用Picker弹窗的时候优先考虑自己使用Picker类组件自行封装。

主要方案就是使用全局自定义弹窗PromptAction.openCustomDialog封装TextPicker组件,然后达成像TextPickerDialog同样的功能,拥有更灵活的自定义能力。

核心代码:

private selectDialogIn: number = 0
private daysDialogIn: string[] = Array(31).fill(0).map((v: string, i) => i + 1).map(n => n.toString());
@State showDayDialogIn: string = ''

@Builder
customDialogComponent() {
  Column() {
    //orange area
    Row() {
      Text(this.showDayDialogIn).fontColor('#FF9A3C').fontSize(15).margin({ left: 10 })
      Text('天以后可以修改').fontColor('#FF9A3C').fontSize(15)
    }
    .height(50).width('100%').alignItems(VerticalAlign.Center).backgroundColor('#FEF2E5')

    // cancal area
    Row() {
      Text('取消').fontColor('#9C9C9C').fontSize(20).margin({ left: 10 })
        .onClick(() => {
          promptAction.closeCustomDialog(this.customDialogComponentId)
          this.showDayDialogIn = ''
        })
      Text('选择持续天数').fontColor('#2D2D2D').fontSize(17)
      Text('确定')
        .fontColor('#507DAF')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ right: 10 })
        .onClick(() => {
          this.showDayDialogIn = ''
          promptAction.closeCustomDialog(this.customDialogComponentId)
        })
    }
    .alignItems(VerticalAlign.Center)
    .justifyContent(FlexAlign.SpaceBetween)
    .width('100%')
    .height(60)

    // textpicker area
    Row() {
      TextPicker({ range: this.daysDialogIn, selected: this.selectDialogIn })
        .onChange((value: string | string[], index: number | number[]) => {
          this.showDayDialogIn = value.toString()
          console.info('Picker item changed, value: ' + value + ', index: ' + index)
        })
        .canLoop(false)
        .divider({
          strokeWidth: '2px',
          startMargin: 20,
          endMargin: 20,
          color: '#33000000'
        })
        .gradientHeight('60%')
        .disappearTextStyle({ color: Color.Black, font: { size: 20, weight: FontWeight.Lighter } })
        .textStyle({ color: Color.Black, font: { size: 20, weight: FontWeight.Lighter } })
        .selectedTextStyle({ color: Color.Black, font: { size: 20, weight: FontWeight.Normal } })
      Text('天').fontSize(20).fontColor(Color.Black)
    }.width('100%').alignItems(VerticalAlign.Center).justifyContent(FlexAlign.Center).margin({ top: 10 })
  }.width('100%').height(360)
}
  • 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.

场景二:自定义CalendarPickerDialog

效果:

效果说明:此处的场景是一个日历选择弹窗,实现了一个类考勤打卡的demo。

基于ArkUI组件picker的自定义实现-鸿蒙开发者社区

基于ArkUI组件picker的自定义实现-鸿蒙开发者社区

方案:

参考场景1方案。此处的picker弹窗也是基于全局自定义弹窗进行封装的,只是不同上面的自定义TextPickerDialog,calendar没有选择使用官方的calendarPicker组件,而是使用三方库直接封装好的,以下demo是参考三方库​​@ohmos/calendar​​实现;当然,开发者也可以自行到三方库中搜寻日历相关关键字,然后挑选适合自己需求的三方库。

核心代码:

@Builder
NormalCalendarBuilder() {
  Column() {
    Row() {
      Text('取消').fontColor('#9C9C9C').fontSize(20).margin({ left: 10 })
        .onClick(() => {
          promptAction.closeCustomDialog(this.normalCalendarDialogId)
        })
      Text('请选择日期').fontSize(17).fontColor('#00aa00').fontWeight(FontWeight.Medium)
      Text('确定')
        .fontColor('#507DAF')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ right: 10 })
        .onClick(() => {
          promptAction.closeCustomDialog(this.normalCalendarDialogId)
        })
    }
    .alignItems(VerticalAlign.Center)
    .justifyContent(FlexAlign.SpaceBetween)
    .width('100%')
    .height(60)

    HmCalendar({
      color: '#00aa00',
      selectedDays: this.normalCalendarSelectedDay,
      onClickDate: (date: string) => {
        let today: HmCalendarSelectedDay = { date: date }
        if (this.normalCalendarSelectedDay.length === 0) {
          this.normalCalendarSelectedDay.push(today)
        }
        // 判断今天是否已经打卡
        if (!this.normalCalendarSelectedDay.includes(today)) {
          this.normalCalendarSelectedDay.push(today)
        }
      }
    })
      .borderRadius(8)
      .border({ width: 0.5, color: '#ededed' })
      .shadow({ color: '#ededed', radius: 16 })
      .height('50%')
  }
  .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.
  • 42.
  • 43.
  • 44.

场景三:多列的TextPicker的实现

效果:

效果说明:文档当中只有最多3列的TextPicker,此处是4列的TextPicker。

基于ArkUI组件picker的自定义实现-鸿蒙开发者社区

基于ArkUI组件picker的自定义实现-鸿蒙开发者社区

方案:

如下代码所示,传入几列的数据,TextPicker就会渲染出几列的数据;且TextPicker中的range是支持二维数组的。

核心代码:

@Entry
@Component
export struct MultipleColumnsTextPicker {
  private cascade: TextCascadePickerRangeContent[] = [
    {
      text: '辽宁省',
      children: [{
        text: '沈阳市',
        children: [{
          text: '沈河区',
          children: [{ text: '大西街道' },
            { text: '滨河街道' },
            { text: '万莲街道' },
            { text: '大南街道' },
            { text: '山东庙街道' },
            { text: '朱剪炉街道' },
            { text: '东陵街道' }]
        }, { text: '和平区' }, { text: '浑南区' }]
      },
        { text: '大连市', children: [{ text: '中山区' }, { text: '金州区' }, { text: '长海县' }] }]
    },
    {
      text: '吉林省',
      children: [{ text: '长春市', children: [{ text: '南关区' }, { text: '宽城区' }, { text: '朝阳区' }] },
        { text: '四平市', children: [{ text: '铁西区' }, { text: '铁东区' }, { text: '梨树县' }] }]
    },
    {
      text: '黑龙江省',
      children: [{ text: '哈尔滨市', children: [{ text: '道里区' }, { text: '道外区' }, { text: '南岗区' }] },
        { text: '牡丹江市', children: [{ text: '东安区' }, { text: '西安区' }, { text: '爱民区' }] }]
    }
  ]

  build() {
    NavDestination() {
      Column() {
        Row() {
          Text('4列TextPicker实现方式')
        }
        .width('100%')
        .height(70)
        .justifyContent(FlexAlign.SpaceAround)
        .alignItems(VerticalAlign.Center)

        TextPicker({ range: this.cascade })
          .onChange((value: string | string[], index: number | number[]) => {
            console.info('TextPicker 多列联动:onChange ' + JSON.stringify(value) + ', ' + 'index: ' +
            JSON.stringify(index))
          })
      }
    }
  }
}
  • 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.

分类
标签
收藏
回复
举报


回复
    相关推荐