Improving UISlider's Precision

UISlider is the standard way of allowing iOS users to choose a numeric value from a given range. The users of my apps, tech bloggers and I have noticed that it doesn't work well if you need to choose the value with a high accuracy. What happens is that when you're lifting up your finger, a thumb (an indicator) tends to jump a little causing a change in the slider's value. This post describes how I analyzed this issue and came up with a workaround.

Observation

I decided to start simple; I wanted to observe how the values change during the touch. To do that, I subclassed UISlider and added a simple logging code by overriding beginTrackingWithTouch:withEvent:, continueTrackingWithTouch:withEvent: and endTrackingWithTouch:withEvent:.

Here's what I've found after a few dozen trials:

  • In most cases the value logged in endTrackingWithTouch:withEvent: was different than the value I'd tried to select. It happened because it's hard to lift up a finger without changing its position.
  • In some cases the last few values logged in continueTrackingWithTouch:withEvent: were also different than the value I'd wanted to select. In these cases, however, touch's location was changing repeatedly (every 0.05s or more often) making it easy to detect and ignore.
  • In all cases the last horizontal position of the touch wasn't farther than 12 points from its position when the desired value had been selected.

Proposed Solution

Considering the above findings I came up with a following algorithm:

  1. During the touch. After each movement, the slider's value and the duration it was present for are stored in an array.
  2. After the touch has ended. The most recent value that was selected for longer than 0.05s is looked up; if it's close enough to the current value (≤ 12 pts), it's assumed to be the value user wanted to select in the first place.

Verification

It's hard to be a 100% sure the proposed solution doesn't break UISlider in some edge cases. Two things are certain, though:

  • improved slider works better in the described case
  • slider's value is corrected only under special circumstances, so other uses should not become broken because of it

You can browse the implementation on GitHub here (look into Classes/ folder). You can also try it quickly with CocoaPods (make sure to run it on a real device as this problem doesn't occur in the simulator):

pod try AHKSlider

Finally, here's a comparison of both behaviors in a short GIF:

Demo GIF