DEV Community

Cover image for Detailed Explanation of HarmonyOS Next Timer Component
kouwei qing
kouwei qing

Posted on

Detailed Explanation of HarmonyOS Next Timer Component

Detailed Explanation of HarmonyOS Next Timer Component

Background Introduction

In daily UI development, timer controls are frequently used. For example, time progress display during video playback and call duration display in audio/video calls require forward-counting timer controls. In some scenarios, countdown timer controls are needed, where a maximum time is set to start the countdown. In Android, we typically use TextView combined with Handler to update the TextView for timing effects. HarmonyOS Next provides the TextTimer component to achieve timing effects. Below is an introduction to the capabilities of TextTimer.

Introduction to TextTimer

TextTimer is a component that displays timing information through text and controls its timer state. When the component is invisible, time changes will stop. The visibility state of the component is handled based on onVisibleAreaChange, and a visibility threshold ratio greater than 0 is considered visible.

Attribute Introduction

  • format(value: string): Sets a custom format, which must include at least one keyword from HH, mm, ss, or SS. If date formats like yy, MM, or dd are used, default values will apply.
  • fontColor(value: ResourceColor): Sets the font color.
  • fontWeight(value: number | FontWeight | string): Sets the font weight of the text. Excessively large values may cause truncation in different fonts. For the number type, values range from [100, 900] with an interval of 100 (default is 400); larger values make the font bolder. The string type supports numeric string forms (e.g., "400") and keywords like "bold", "bolder", "lighter", "regular", and "medium", corresponding to the respective enumeration values in FontWeight.
  • fontFamily(value: ResourceStr): Sets the font list, with the default font being 'HarmonyOS Sans'. Applications currently support 'HarmonyOS Sans' and registered custom fonts, while cards only support 'HarmonyOS Sans'.
  • textShadow(value: ShadowOptions | Array<ShadowOptions>): Sets text shadow effects. This interface supports array parameters for multiple shadows, but does not support the fill field or intelligent color pickup mode.
  • contentModifier(modifier: ContentModifier<TextTimerConfiguration>): A method to customize the content area of TextTimer, where modifier is a content modifier that developers need to implement by defining a class that adheres to the ContentModifier interface.

The TextTimer constructor requires a TextTimerOptions object, which includes the following attributes:

Name Type Required Description
isCountDown boolean No Indicates whether to use countdown. When true, the timer starts counting down; when false, it starts counting up.

Default: false
count number No Timer duration (effective when isCountDown is true), in milliseconds. The maximum duration is 86,400,000 milliseconds (24 hours). When 0 < count < 86,400,000, count is the initial timer value; otherwise, the default value is used.

Default: 60000
controller TextTimerController No The TextTimer controller, used to start, pause, etc.

The TextTimerController mainly controls the timer:

  • start(): Starts the timer.
  • pause(): Pauses the timer.
  • reset(): Resets the timer.

Event Introduction

The main event is onTimer:

  • onTimer(event: (utc: number, elapsedTime: number) => void): Triggered when the time text changes. This event is not triggered when the screen is locked or the app is in the background. When setting high-precision formats (SSS, SS), the callback interval may fluctuate. The parameter utc is a Linux timestamp (time elapsed since January 1, 1970) in the minimum unit of the set format; elapsedTime is the elapsed time of the timer, also in the minimum unit of the set format.

Usage Examples

Example 1: Button-Controlled Timer

@Entry
@Component
struct TextTimerExample {
  textTimerController: TextTimerController = new TextTimerController()
  @State format: string = 'mm:ss.SS'

  build() {
    Column() {
      TextTimer({ isCountDown: true, count: 30000, controller: this.textTimerController })
        .format(this.format)
        .fontColor(Color.Black)
        .fontSize(50)
        .onTimer((utc: number, elapsedTime: number) => {
          console.info('textTimer notCountDown utc is:' + utc + ', elapsedTime: ' + elapsedTime)
        })
      Row() {
        Button("start").onClick(() => {
          this.textTimerController.start()
        })
        Button("pause").onClick(() => {
          this.textTimerController.pause()
        })
        Button("reset").onClick(() => {
          this.textTimerController.reset()
        })
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Effect:

Example 2: Automatic Timing

@Entry
@Component
struct TextTimerStart {
  textTimerController: TextTimerController = new TextTimerController()
  @State format: string = 'mm:ss.SS'

  build() {
    Column() {
      Scroll()
        .height('20%')
      TextTimer({ isCountDown: true, count: 30000, controller: this.textTimerController })
        .format(this.format)
        .fontColor(Color.Black)
        .fontSize(50)
        .onTimer((utc: number, elapsedTime: number) => {
          console.info('textTimer notCountDown utc is:' + utc + ', elapsedTime: ' + elapsedTime)
        })
        .onAppear(() => {
          this.textTimerController.start()
        })
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Usage Limitations

For forward-counting scenarios, the timer always starts from 0, but some scenarios require starting from a specific time. For example, in page switching during a video call, the full-screen and floating-window pages should have continuous timing instead of restarting from 0. How to achieve this?

TextTimer provides a content area customization method contentModifier, which requires implementing ContentModifier<TextTimerConfiguration>:

  1. First, implement MyTextTimerModifier and encapsulate the Builder method in the applyContent method.
  2. Customize the UI in the custom Builder method.
  3. Configure the custom MyTextTimerModifier to TextTimer using contentModifier.
  4. Remove color and font configurations from TextTimer and configure them in the custom UI.
  5. The format setting affects the unit of elapsedTime.
  6. Adding an initial value to config.elapsedTime starts timing from a specific time.
  7. Convert seconds to the mm:ss format.

Code example:

let startTime: number = 100;  

function formatData(diffTimeBySecond: number): string {  
  const hours = Math.floor(diffTimeBySecond / 3600);  
  const minutes = Math.floor((diffTimeBySecond % 3600) / 60);  
  const remainingSeconds = Math.floor(diffTimeBySecond % 60);  

  // Zero-padding function  
  const pad = (num: number) => num.toString().padStart(2, '0');  

  return hours > 0  
    ? `${pad(hours)}:${pad(minutes)}:${pad(remainingSeconds)}`  
    : `${pad(minutes)}:${pad(remainingSeconds)}`;  
}  
class MyTextTimerModifier implements ContentModifier<TextTimerConfiguration> {  
  constructor() {  
  }  
  applyContent(): WrappedBuilder<[TextTimerConfiguration]> {  
    return wrapBuilder(buildTextTimer)  
  }  
}  

@Builder  
function buildTextTimer(config: TextTimerConfiguration) {  
  Column() {  
      Column() {  
        Text(formatData(config.elapsedTime + startTime)).fontColor(Color.Red)  
    }  
  }}  

@Entry  
@Component  
struct Index {  
  @State count: number = 10000  
  @State myTimerModifier: MyTextTimerModifier = new MyTextTimerModifier()  
  countUpTextTimerController: TextTimerController = new TextTimerController()  

  build() {  
    Row() {  
      Column() {  
        TextTimer({ isCountDown: false, controller: this.countUpTextTimerController })  
          .contentModifier(this.myTimerModifier)  
          .onTimer((utc: number, elapsedTime: number) => {  
            console.info('textTimer onTimer utc is:' + utc + ', elapsedTime: ' + elapsedTime)  
          })  
        Row() {  
          Button("start").onClick(() => {  
            this.countUpTextTimerController.start()  
          }).margin(10)  
          Button("pause").onClick(() => {  
            this.countUpTextTimerController.pause()  
          }).margin(10)  
          Button("reset").onClick(() => {  
            this.countUpTextTimerController.reset()  
          }).margin(10)  
        }.margin(20)  
      }.width('100%')  
    }.height('100%')  
  }  
}
Enter fullscreen mode Exit fullscreen mode

Final effect:

Top comments (0)