DEV Community

HarmonyOS
HarmonyOS

Posted on

How to determine whether the slider or the progress bar is clicked when using Slider

Read the original article:How to determine whether the slider or the progress bar is clicked when using Slider

Context

When implementing media player controls or similar interactive components in HarmonyOS, developers often need to differentiate between user interactions with the slider block (thumb) versus the progress bar (track). A common requirement is to pause or resume playback when clicking the slider block, while clicking the progress bar should seek to that position. However, the standard Slider component doesn't provide a direct way to distinguish between these two types of clicks, requiring a custom detection mechanism.

Description

The HarmonyOS Slider component is typically used for quickly adjusting setting values in scenarios such as volume control, brightness adjustment, and media playback progress.

The SliderChangeMode enumeration represents the slider's state values, which can be obtained through the onChange event when the Slider is dragged or clicked. The modes include:

  • Begin: User presses down on the slider
  • Moving: User is dragging the slider
  • End: User releases the slider
  • Click: User clicks on the slider track

The Challenge:

When a user clicks the slider block without dragging, the progress value doesn't change. However, clicking the slider track moves the block to that position, causing the progress value to change. The requirement is to detect which element was clicked to implement different behaviors (e.g., pause/resume for block clicks, seek for track clicks).

Solution

The solution leverages the fact that clicking the slider block without movement doesn't change the progress value, while clicking the track does. By comparing the progress value before and after the press action in the onChange event, we can determine whether the user clicked the block or the track.

Implementation Logic:

  1. Capture the slider value when the user presses down using the onChange event with SliderChangeMode.Begin
  2. Compare the current value with the previous value (lastValue):
    • If values are identical: user clicked the slider block
    • If values differ: user clicked the slider track
  3. When the user releases (SliderChangeMode.End), store the current value as lastValue for the next comparison

Complete Code Example:

// Complete code example
@Entry
@Component
struct SliderClickDetector {
  @State value: number = 30; // Initial value
  lastValue: number = 30; // Record the last slider value
  @State sliderState: string = ''; // Slider state

  build() {
    Column() {
      // Display current progress value
      Text(`Click Position: ${this.value.toFixed(0)}%`)
        .fontSize(20)
        .margin(20)

      // Core Slider component
      Slider({
        value: $$this.value,
        min: 0,
        max: 100,
        step: 1,
        style: SliderStyle.OutSet // Use raised style
      })
        .width('90%') // Set Slider width
        .onChange((value, mode) => {
          if (mode === SliderChangeMode.Begin) {
            if (value === this.lastValue) {
              this.sliderState = 'Clicked slider block'
            } else {
              this.sliderState = 'Clicked slider track'
            }
          }
          if (mode === SliderChangeMode.End) {
            this.lastValue = value
          }
        })

      Text(`Click Location: ${this.sliderState}`)
        .fontSize(16)
        .margin(15)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}
Enter fullscreen mode Exit fullscreen mode

How It Works:

  1. Initialization: Both value and lastValue start at 30 (or any initial position)
  2. Begin Event: When user presses down, compare current value with lastValue
    • Same values → slider block was clicked
    • Different values → slider track was clicked (value jumped to click position)
  3. End Event: Store the final value in lastValue for next comparison
  4. State Display: Show the detected click type in real-time for debugging or user feedback

Practical Application for Media Player:

.onChange((value, mode) => {
  if (mode === SliderChangeMode.Begin) {
    if (value === this.lastValue) {
      // Clicked slider block - toggle play/pause
      this.togglePlayPause()
    } else {
      // Clicked slider track - seek to position
      this.seekToPosition(value)
    }
  }
  if (mode === SliderChangeMode.End) {
    this.lastValue = value
  }
})
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • Use SliderChangeMode.Begin to detect the initial press event and compare values immediately to distinguish click types
  • Store the slider value in a non-state variable (lastValue) to avoid triggering unnecessary re-renders during comparison
  • The key insight is that clicking the block doesn't change the value, while clicking the track does - this behavioral difference enables detection
  • Use SliderChangeMode.End to update the stored value after any interaction completes, ensuring the next comparison is accurate
  • The $$ two-way binding syntax ($$this.value) ensures the slider value stays synchronized with the state variable
  • This pattern can be extended to implement different behaviors: pause/resume on block click, seek on track click, or show/hide additional controls
  • Always initialize both the state value and the tracking variable to the same value to ensure correct first-click detection
  • Consider using SliderStyle.OutSet for better visual feedback, making it clearer when users click the block versus the track

Written by Emincan Ozcan

Top comments (0)