自定义组件—基于TimePIcker或DatePicker实现时间或日期选择组件 原创

在敲键盘的小鱼干很饥饿
发布于 2024-12-30 17:14
浏览
1收藏

1. 效果演示

日期选择组件实现
自定义组件—基于TimePIcker或DatePicker实现时间或日期选择组件-鸿蒙开发者社区
时间选择组件实现
自定义组件—基于TimePIcker或DatePicker实现时间或日期选择组件-鸿蒙开发者社区

2. 引言

在项目开发中遇到需要时间或日期的组件,于是查阅文档,发现了DatePickerDialog/TimePickerDialog两个选择器弹窗,然而在实际的使用过程中发现他们不是太好使用,且只能是弹窗的形式。于是再次查阅文档发现TimePicker和DatePicker选择组件于是在此基础上再次自定义样式,实现符合自己需求的选择器样式。
本文将深入探讨如何自定义基于TimePicker和DatePicker的组件,以满足不同场景下的需求。通过这两个组件,开发者可以实现灵活的时间和日期选择功能,使得用户操作更加便捷和高效。

3. 组件概述

在本节中,我们将对TimePickerComponents和DatePickerComponents这两个自定义组件进行概述,了解它们的功能、结构以及在实际项目中的应用场景。

3.1 TimePickerComponents

TimePickerComponents是一个用于选择时间的组件,主要功能是允许用户设定出发时间。这一组件设计得非常简洁,用户可以轻松地选择所需的时间,然后通过“确定”或“取消”按钮进行确认或放弃选择。
主要特性:

  • 时间选择:用户能够以小时和分钟为单位选择时间,采用24小时制的显示方式。
  • 样式定制:组件支持自定义样式,包括文本颜色、字体大小、按钮样式等,以符合整体应用的设计风格。
  • 回调函数:组件提供confirm和closeBox两个回调函数,分别用于处理用户确认选定时间和关闭组件的操作。

3.2 DatePickerComponents

DatePickerComponents是用于选择日期的组件,专为方便用户设定旅行日期而设计。通过一个直观的界面,用户可以选择起始和结束日期,从而进行个性化的行程安排。
主要特性:

  • 样式定制:同样支持自定义样式,帮助开发者调整组件外观,以适应不同的UI设计。
  • 日期变化监听:通过.onDateChange事件,组件能够实时监控用户选择的日期,并立即更新内部状态。

这两个组件不仅功能强大,而且它们的实现逻辑清晰,使得开发者可以轻松集成到现有的项目中。在接下来的部分,我们将对TimePickerComponents进行详细解析,分析其结构、属性和交互设计,帮助开发者更好地理解其内部工作原理。

4. TimePickerComponents 详解

先直接给出示例代码

@Entry
@Component
export struct TimePickerComponents {
  private selectedTime: Date = new Date('2025-12-10T08:30:00')
  confirm: ((time: Date) => void) | undefined = undefined
  closeBox: (() => void)| undefined = undefined
  build() {
    Column() {
      Text("设置出发时间")
        .fontColor(Color.Black)
        .fontSize(16)
        .width("100%")
        .height('10%')
        .padding({left: 11, top: 6})

      Column(){
        TimePicker({
          selected: this.selectedTime,
          format: TimePickerFormat.HOUR_MINUTE,
        })
          .useMilitaryTime(true)
          .onChange((value: TimePickerResult) => {
            if(value.hour >= 0) {
              this.selectedTime.setHours(value.hour, value.minute)
              console.info('select current date is: ' + JSON.stringify(value))
            }
          })
          .disappearTextStyle({color: "#F6F6F6", font: {size: 18, weight: FontWeight.Lighter}})
          .textStyle({color: "#858585", font: {size: 18, weight: FontWeight.Normal}})
          .selectedTextStyle({color: "#000000", font: {size: 18}})
          .width("76%")
          .height("74%")

        Row(){
          Button("取消", { type: ButtonType.Normal })
            .margin({left: 30})
            .backgroundColor($r("app.color.cancel_background2"))
            .fontColor($r("app.color.font_color"))
            .fontSize(18)
            .borderRadius(5)
            .height(34)
            .width('33%')
            .onClick(() => {
              if(this.closeBox){
                this.closeBox()
              }
            })

          Button("确定", { type: ButtonType.Normal})
            .margin({right: 30})
            .fontColor($r("app.color.confirm_font"))
            .linearGradient({
              direction: GradientDirection.Left,
              colors: [[$r("app.color.confirm_background1"), 0.0], [$r("app.color.confirm_background2"), 1.0]]
            })
            .fontSize(18)
            .borderRadius(5)
            .height(34)
            .width('33%')
            .onClick(() => {
              if(this.confirm){
                this.confirm(this.selectedTime);
              }
            })
        }
        .defaultFocus(true)
        .height("26%")
        .width("100%")
        .justifyContent(FlexAlign.SpaceBetween)
      }
      .height("50%")
      .width("100%")
      .alignItems(HorizontalAlign.Center)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r("app.color.plan_item_background"))
  }
}

属性方面有

  • selectedTime:这个私有属性用于存储用户当前选择的时间,初始化为一个特定的日期和时间(如2025-12-10T08:30:00)。在组件创建时,该时间用于填充时间选择器。
  • confirm和closeBox:这两个属性分别为回调函数,用户可以在点击“确定”或“取消”按钮时调用它们。这允许父组件实现对所选时间的处理或关闭时间选择器的功能。

4.1 时间选择的实现

TimePicker({
  selected: this.selectedTime,
  format: TimePickerFormat.HOUR_MINUTE,
})
  .useMilitaryTime(true)
  .onChange((value: TimePickerResult) => {
    if (value.hour >= 0) {
      this.selectedTime.setHours(value.hour, value.minute);
      console.info('select current date is: ' + JSON.stringify(value));
    }
  })
  • 时间选择器配置:通过传入selected属性,时间选择器知道当前选定的时间是什么;format定义了时间的显示格式。
  • 时间格式:调用.useMilitaryTime(true)使得时间选择器以24小时制显示时间。
  • 时间变更监听:.onChange事件监听用户在时间选择器中的选择,当用户选择新的时间时,这个事件将被触发。我们使用setHours方法来更新selectedTime属性,以确保每次选择后组件状态的一致性。

4.2 交互设计

Row() {
  Button("取消", { type: ButtonType.Normal })
    .onClick(() => {
      if (this.closeBox) {
        this.closeBox();
      }
    });
    
  Button("确定", { type: ButtonType.Normal })
    .onClick(() => {
      if (this.confirm) {
        this.confirm(this.selectedTime);
      }
    });
}

按钮具体样式实现看前面的具体代码

  • “取消”按钮:当用户点击此按钮时,调用closeBox回调函数,允许父组件处理关闭操作。这对用户非常友好,允许他们轻松返回而不必进行选择。
  • “确定”按钮:此按钮在用户点击后会调用confirm回调,传递当前选择的时间。这一机制使得父组件能够接收并处理所选时间,可以进行后续的业务逻辑处理,例如保存到数据库或用于界面更新。

4.3 TimePicker属性介绍

这里只介绍一些最新的属性供大家使用

  • disappearTextStyle10+ 设置所有选项中最上和最下两个选项的文本颜色、字号、字体粗细。
  • textStyle10+ 设置所有选项中除了最上、最下及选中项以外的文本颜色、字号、字体粗细。
  • selectedTextStyle10+ 设置选中项的文本颜色、字号、字体粗细。
  • loop11+ 设置是否启用循环模式。
  • dateTimeOptions12+ 设置时分秒是否显示前置0。

5. DatePickerComponents 详解

DatePicker组件和上面的TimePicker并未太大差别,这里介绍一下实现和属性。

5.1 日期选择的实现

        DatePicker({
          start: new Date('1970-1-1'),
          end: new Date('2100-1-1'),
          selected: this.selectedDate
        })
          .disappearTextStyle({color: "#F6F6F6", font: {size: 18, weight: FontWeight.Lighter}})
          .textStyle({color: "#858585", font: {size: 18, weight: FontWeight.Normal}})
          .selectedTextStyle({color: "#000000", font: {size: 18}})
          .lunar(false)
          .width("76%")
          .height("74%")
          .onDateChange((value: Date) => {
            this.selectedDate = value
          })
  • 日期选择器配置:start和end属性定义了日期选择的范围,这里的范围覆盖了从1970年到2100年的所有日期,确保了用户选择的灵活性。selected属性指定了当前选定的日期。
  • 日期变化监听:通过.onDateChange事件来监听用户的日期选择并更新selectedDate属性。当用户选择新的日期时,系统会自动更新该属性,以保持状态的一致性。

5.2 DatePicker属性介绍

  • lunar 设置弹窗的日期是否显示农历。
  • disappearTextStyle10+ 设置所有选项中最上和最下两个选项的文本样式。
  • textStyle10+ 设置所有选项中除了最上、最下及选中项以外的文本样式。
  • selectedTextStyle10+ 设置选中项的文本样式。

6. 使用示例

这里我以时间组件的使用为例
具体示例:自定义弹窗

@CustomDialog
struct TimpickerDialog{
  @Link dayPlayPlaces: Array<Array<PlayPlace>>;
  @Link selectDayBtn: number;
  @Link idCityTitleModel: IdCityTitleModel;
  @Link timeCnt: Array<string>;
  controller: CustomDialogController;

  build() {
    TimePickerComponents({
      confirm: async (time: Date) => {
        console.log("===选择出发时间" + time.toString());
        let temp = this.dayPlayPlaces[this.selectDayBtn];
        let timeString = `${time.getHours() > 9 ? time.getHours() : "0" + time.getHours()}:${time.getMinutes() > 9 ? time.getMinutes() : "0" + time.getMinutes()}`;
        console.log("===" + await updateStartTime(this.idCityTitleModel.routeId, timeString, this.selectDayBtn + 1));
        this.timeCnt = await arrivalTime(this.idCityTitleModel.routeId, this.selectDayBtn + 1);
        temp.forEach((_, idx) => { temp[idx].time = timeString; });
        this.dayPlayPlaces.splice(this.selectDayBtn, 1, temp);
        this.controller.close();
      },
      closeBox: () => { this.controller.close(); }
    })
  }
}

// 调用弹窗的示例
Text(this.dayPlayPlaces[this.selectDayBtn][0].time)
  .fontSize(16)
  .fontColor($r("app.color.time"))
  .margin({ left: 8.76 })
  .onClick((event: ClickEvent) => {
    this.offSetX = event.windowX - 90;
    this.offSetY = event.windowY - 555;
    if (this.offSetY >= 25) this.offSetY -= 270;

    this.dialogController = new CustomDialogController({
      builder: CustomDialogExample({
        dayPlayPlaces: this.dayPlayPlaces,
        selectDayBtn: this.selectDayBtn,
        idCityTitleModel: this.idCityTitleModel,
        timeCnt: this.timeCnt
      }),
      cancel: () => {},
      autoCancel: true,
      onWillDismiss: (dismissDialogAction: DismissDialogAction) => {
        console.info("reason=" + JSON.stringify(dismissDialogAction.reason));
        console.log("dialog onWillDismiss");
        if (dismissDialogAction.reason == DismissReason.PRESS_BACK || dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
          dismissDialogAction.dismiss();
        }
      },
      alignment: DialogAlignment.Bottom,
      offset: { dx: this.isFullScreen ? 0 : this.offSetX, dy: this.isFullScreen ? -23 : this.offSetY },
      gridCount: 4,
      customStyle: false,
      cornerRadius: 10,
      width: 255,
      height: 240,
    });

    if (this.dialogController != null) {
      this.dialogController.open();
    }
  })

  • TimepickerDialog 结构
    该结构实现了TimePickerComponents,并为用户选择时间提供了交互界面。用户选择确认后,时间会更新到对应的dayPlayPlaces项中。
  • 时间文本点击事件:
    通过点击动态生成的时间文本以打开弹窗,用户可以在其中选择出发时间。这里采用了点击事件,能根据用户当前位置调整弹窗显示位置。这个弹窗显示位置跟随主弹窗,可以看团队另外一篇博客。OpenHarmony之跟随弹窗CustomDialog(详细代码实现+运行实例
  • 对话框的管理:
    通过CustomDialogController,您可以灵活控制对话框的打开、关闭,以及关闭时的各种处理。此设计确保用户拥有良好的交互体验。

当然也可以使用封装成半模态弹窗,关于半模态弹窗的实现,可以看我的这一篇文章ArkUI框架下半模态弹窗的自定义设计指南:打造丝滑的用户体验 在这篇文章就只介绍自定义弹窗的实现了。

7. 总结

在本文中,我们详细探讨了如何使用自定义组件TimePickerComponents与DatePickerComponents来实现时间和日期选择功能。通过分析代码结构、交互设计以及样式设置,我们展示了如何将这些组件灵活地应用到实际项目中,以提升用户体验。最后恳请大家点赞。互相学习分析。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2024-12-30 17:14:37修改
收藏 1
回复
举报
回复
    相关推荐