DEV Community

HarmonyOS
HarmonyOS

Posted on

Implement a custom time sliding selector pop-up window

Read the original article:Implement a custom time sliding selector pop-up window

Context

In a development scenario, a date selection feature needs to be implemented. A button or icon is provided on the interface, and when clicked, it should display a date picker that shows the current date and allows the user to select a date starting from today.

Description

  • TimePicker is a time selection component used to create a picker based on specified parameters. It supports selecting hours and minutes.
  • DatePicker is a date selection component used to create a scrollable date picker within a specified date range.

Solution

Use the TextPicker on the main interface to trigger a pop-up. A custom dialog component, TextPicker1, can be used to host the date selection functionality. During this process, CustomDialogController and callback functions should be used to establish effective communication between components, ensuring that the selected date in the dialog is promptly passed back and displayed on the main interface.

let anmDuration: number = 200;

@Entry
@Component
struct TextPickerExample1 {
  @State firstDate: string = '2024-06-19'
  @State date: string = 'June 19, 2024'
  controller: CustomDialogController = new CustomDialogController({
    builder: TextPicker1({
      cancel: (date: string) => {
        this.onCancel(date)
      },
      confirm: (date: string, date1: Date) => {
        this.onAccept(date, date1)
      },
      date: this.firstDate,
    }),
    autoCancel: false,
    cornerRadius: 0,
    customStyle: true,
    alignment: DialogAlignment.BottomEnd
  })

  onCancel(date: string) {
    // Handle cancel if needed
  }

  onAccept(date: string, date1: Date) {
    let year: string = date1.getFullYear().toString();
    let month: string =
      (date1.getMonth() + 1) < 10 ? ('0' + (date1.getMonth() + 1)).toString() : (date1.getMonth() + 1).toString();
    let day: string = date1.getDate().toString();
    this.date = year + 'year' + month + 'month' + day + 'day' 
    this.firstDate = year + '-' + month + '-' + day   
  }

  build() {
    Column() {
      Text(this.date)
      Text('Date').onClick(() => { 
        this.controller.open()
      })
    }
  }
}

@CustomDialog
struct TextPicker1 {
  aboutToAppear(): void {
    this.selectedDate = new Date(this.date)
  }

  @State date: string = '2026-08-08'
  controller: CustomDialogController = new CustomDialogController({ builder: ()=>{} })
  @State startYear: number = 1970           // Start year
  @State isLunar: boolean = false
  @State showFlag: Visibility = Visibility.Visible
  @State isAutoCancel: boolean = false
  @State selectedDate: Date = new Date(this.date)
  cancel?: (date: string) => void
  confirm?: (date: string, date1: Date) => void

  // Delay closing the dialog to allow custom exit animation to show
  @State nowDate: Date = new Date()

  destroy() {
    this.showFlag = Visibility.Hidden
    setTimeout(() => {
      this.controller.close()
    }, anmDuration)
  }

  build() {
    Column() {
      Column() {
        Row() {
          Button('Cancel', { type: ButtonType.Normal }).backgroundColor(Color.White).fontColor(Color.Gray)
            .onClick(() => {
              if (this.cancel) {
                this.destroy();
                this.cancel(this.date)
              }
            })
          Button('Confirm', { type: ButtonType.Normal }).backgroundColor(Color.White).fontColor("#fff5b6dd")
            .onClick(() => {
              if (this.confirm) {
                this.destroy();
                this.date = this.nowDate.toString()
                this.confirm(this.date, this.nowDate)
              }
            })
        }.width('100%').justifyContent(FlexAlign.SpaceBetween)

        DatePicker({
          start: new Date('1970-1-1'),
          end: new Date('2100-1-1'),
          selected: this.selectedDate
        })
          .disappearTextStyle({ color: Color.Gray, font: { size: '16fp', weight: FontWeight.Bold } })
          .textStyle({ color: '#ff182431', font: { size: '16', weight: FontWeight.Normal } })
          .selectedTextStyle({ color: "#fff5b6dd", font: { size: '22fp', weight: FontWeight.Regular } })
          .lunar(this.isLunar)
          .onDateChange((value: Date) => {
            this.nowDate = value
            console.info('Selected date: ' + value.toString())
          })
      }
    }.width('100%').backgroundColor(Color.White).visibility(this.showFlag)
    // Define entrance and exit transition effects
    .transition(TransitionEffect.OPACITY.animation({ duration: anmDuration })
      .combine(TransitionEffect.translate({ y: 100 })))
  }
}

Enter fullscreen mode Exit fullscreen mode

The effect is as follows for mobile and wearable devices:

Key Takeaways

  • Q: How can I implement synchronized selection of both date and time? A: For synchronized date and time selection, please refer to the documentation for the date picker pop-up.
  • Q: Does the time picker support selection down to seconds? A: When using the time picker, if you need precision down to the second, you can set the configuration option containSecond to true. If seconds are not needed, set it to false. For detailed operations, refer to the relevant documentation: TimePicker

Additional Resources

Written by Hatice Akyel

Top comments (0)