LVGL Range Sliders: Define Which Limit Moves When Handles Meet

A two-handle slider needs a numeric contract before it needs a visual treatment. Define low ≤ high, decide whether equality is valid, and identify which endpoint the current interaction owns. Test both user movement and programmatic pair updates: the widget’s endpoint clamping can make setter order significant.

Applicability: this procedure uses LVGL v9.3.0 in LV_SLIDER_MODE_RANGE, with a fixed ascending domain, horizontal left-to-right layout and no transforms. The hypothetical domain is 0 through 100. Dynamic domain changes, reversed ranges and other orientations require additional qualification. No pointer or keyboard fixture was executed.

Two contact tests preserve endpoint identity; separate upward and downward interval replacement examples show why setter order matters.
Original proposed fixed-domain fixture. Equality is an example product policy; animations and reverse/orientation variants are outside the initial test.

1. Name endpoints by meaning

The 9.3 slider reference describes range mode with two values. Bind the lower endpoint to the start value and the upper endpoint to the ordinary value. The tagged API exposes the start-value setter and left-value getter alongside the ordinary value operations.

Use low and high in the model, even though an API name says left. Visual left/right can change with direction or orientation settings; numeric identity should not silently change with localization. Label the displayed quantities with their meaning, such as lower acceptance limit and upper acceptance limit.

For the worked policy, equality is permitted and represents a zero-width interval. If the application instead requires a minimum gap, specify that as another model invariant. The built-in no-crossing behavior does not establish an arbitrary required separation.

2. Understand clamping at contact

The v9.3.0 bar implementation underlying the slider prevents the ordinary value from falling below the start value and the start value from rising above the ordinary value. The pointer path applies corresponding endpoint limits. Crossing does not automatically exchange low and high identities or push the other endpoint along.

For a hypothetical interval [30, 70], dragging low toward 80 should stop low at 70 while high stays 70. Dragging high toward 20 should stop high at 30 while low stays 30. Those are independent tests from separate initial states. Record both values after every admitted change, not only the handle under the finger.

If the product requires a push-the-other-handle interaction, implement and qualify that explicitly at the model boundary. Do not infer it from the fact that both knobs occupy one widget. Similarly, enforcing a minimum gap by correcting values inside a callback needs a reentrancy policy and should not generate two externally committed settings.

3. Qualify handle choice when geometry is ambiguous

The tagged slider implementation chooses an endpoint when a drag starts. In its nearest-knob branch, equal distances select the start endpoint. This matters when knobs coincide. It is a branch-specific source fact, not a promise that every touch anywhere on an overlapping control chooses low.

Build the fixture after layout and a draw have established the knob areas. Start with a press at the coincident centers, then move left and right in separate runs. Also press just to either side and outside the knob extents. Compare the chosen endpoint and resulting pair with the written policy.

Once a drag has selected an endpoint, continue through contact and reversal without releasing. Then release and begin a new drag at the same position. A second interaction can make a new selection; it should not be assumed to inherit the previous endpoint merely because the coordinates match.

4. Update a pair without accidental clipping

Consider programmatically replacing [20, 40] with [60, 80]. Setting low to 60 first is constrained by the old high of 40; setting high to 80 afterward leaves an unintended low of 40. For this disjoint upward move, set high first, then low. Read both values back before considering the update complete.

The opposite move also matters. Replacing [60, 80] with [20, 40] requires lowering low before lowering high, otherwise the old low can constrain the first high update. These examples use a fixed domain and animations disabled to isolate endpoint logic.

A general application transaction can first expand the existing interval enough to contain the destination, then set the final endpoints. Keep the model’s validated destination pair authoritative and suppress intermediate external commits while applying the widget updates. This is application transaction logic, not an atomic two-value LVGL setter.

Do not use a pair-update recipe as a substitute for validating a new domain. Changing minimum/maximum while retaining an old start value is a different source path. Reinitialize or explicitly reconcile all values under a separately tested policy if the product supports that operation.

5. Include non-pointer input

The pinned slider key handler adjusts the endpoint selected by its internal knob-focus state; focus and encoder editing can influence that selection. Do not assume a successful pointer drag demonstrates that both limits are reachable from the keypad or encoder workflow.

For each supported input method, establish which endpoint is selected, issue one increase and one decrease, and inspect the numeric pair. Repeat at equality and at both domain ends. Verify that the visible low/high label follows the endpoint actually changed. The task here is numeric endpoint identity, not a general focus-navigation redesign.

Proposed case Required evidence
Low approaches high Low stops at high; high unchanged
High approaches low High stops at low; low unchanged
Coincident-center press Recorded selection agrees with the pinned branch
Disjoint upward pair update [20,40] becomes exactly [60,80]
Disjoint downward pair update [60,80] becomes exactly [20,40]
Key adjustment at equality Selected endpoint moves only within the invariant

6. Separate preview from a committed limit pair

Decide whether VALUE_CHANGED updates a preview or immediately changes the application model. A setting consumed by another subsystem should be transmitted as one coherent low/high pair with a model revision, not as two unrelated messages that can be observed out of order.

Test cancellation, loss of press and a concurrent external model update according to the chosen commit policy. Avoid deriving physical precision from pixel width alone: multiple numeric values can map to indistinguishable handle positions. Keep exact numeric labels and an alternative fine-adjustment route when the product requires it.

The acceptance artifact is a fixed-domain invariant, endpoint-selection trace and pair-update matrix. Pass the control when low and high retain their meaning through contact, equality, reversal and programmatic replacement, rather than when the highlighted span merely looks reasonable.

Similar Posts