I’ve been working on subclassing and improving the venerable UISlider class in iOS’s UIKit framework.
Here’s what I was thinking: UISlider is a great way for the user to enter numerical values within a certain range very quickly. It’s immediately responsive and by default gives continual updates as to its value. The problem is that it’s not really all that accurate. There are two ways in which the slider manifests inaccuracies:
- Though the value reported by the control is a float, there are only so many physical pixel positions upon which the thumb can lie along the track. In the example above, the slider is 284 points wide. Subtract 11.5 points from either side (these are the areas where the thumb can’t go) and you have 261 discrete positions along the track where the thumb can physically sit and indicate value. If the minimum and maximum values are, say, 100 and 1000 then we’re talking 3.4 value units for each point of physical space on the track.
- Even if you can get really accurate with your finger, chances are the value is going to change slightly when you lift up your finger. This is a byproduct of how positions are reported by the hardware.
There are only two values that are selectable with very gross accuracy: the minimum and the maximum.
It seemed like Apple even acknowledged this deficiency starting with iOS 4. If you use the scrubber in the Music (or iPod) app, you can change scrubbing accuracy of the slider by moving your finger perpendicular away from the track. As you move, you get textual feedback (two lines of text; one above the track and one below) telling you about how the slider is behaving.
I thought this was a really interesting solution to the problem of slider accuracy, but I thought that there were two things about Apple’s implementation that were not quite right:
- There is no visibly obvious way for the user to know that the slider works in a unique way.
- The only hint that it does work in a unique way are the two lines of text, the one on top indicates the current scrubbing speed, the one on the bottom describes how to use the control.
It seems to me that if you have to use two lines of text to describe how a control works, you have failed. So, here is my attempt at improving the control:
I thought Ole Begemann’s open source implementation of this in UISlider was really cool but I wanted to improve it even further. I wanted continuously increasing accuracy (instead of steps like in Ole’s version) and I wanted visual feedback indicating what was going on with the control (Ole’s version has no special appearance to it.)
What I have created is a subclass of UISlider that improves its functionality. Here’s how:
- By itself (when you’re not interacting with it) the slider looks totally normal.
- As soon as you touch the thumb, two indicators appear (actually, they fade in over 0.2 seconds.) They resemble the jaws of a caliper.
- The job of these two indicators is to display to the user how accurate the slider is behaving. As your finger moves up (or down) away from the track, the jaws move inward to indicate that the “area of concern” on the track is shrinking. The thumb moves markedly slower than the users finger. The areas of track outside the “area of concern” are dimmed to indicate that they are not selectable at the current level of accuracy. As the user’s finger gets further and further from the track, the jaws move even further inward and the accuracy of the thumb (including the value extracted programmatically) increases dramatically.
- When the user releases their finger, the jaws and disabled areas of track move back to their original positions and fade out.
- There is a vertical 20pt or so “dead zone” along the track where accuracy is totally normal (i.e.; not fine.) This allows the control to work “mostly as normal” yet the appearance of the caliper jaws gives the user the idea that something more might be going on.
As I was building this, I was thinking (hypothesizing) that if I got this right, that would make the slider a really good way of entering numerical data. It seemed like one could easily get accurate numeric data entered quickly.
So, I built it (well, there’s still a bit of work to do but it’s close enough to “done” to test) and decided to actually test to see how well it worked.
I built an iPhone project in Xcode that had 4 tab views. Each tab view had a unique method of entering numeric information and I programmed each one to record how long it took for the user to enter the specific numeric value we wanted. The 4 methods were:
- UISlider (min:1, max: 100)
- UIAccurateSlider (my special subclass, same values as above)
- UIPickerView (4 wheels: two single digit wheels, a period, and a final digit wheel)
- UITextField (with numeric keyboard popup.)
I tested on myself and was stunned at what I saw. After trying it a bunch of times, here are some rough ideas about how long it took for me to enter the value of 84.3:
- UISlider: gave up
- UIAccurateSlider: 13 seconds
- UIPickerView: 6 seconds
- UITextField: 3 seconds
Now, this is kind of a “best case scenario” with a user who is not only good with computer, but also wrote how one of them behaves.
I guess I was hoping that my fancy, more accurate UISlider would be so awesome that it could almost replace any kind of text input area (at least where values sit within certain reasonable ranges.) I was totally stunned at how long it took to enter accurate values with my special slider subclass.
Now, to be fair, the accurate slider I made has benefits that the UIPickerView wheels and the UITextField keyboard doesn’t, most notably, interactivity. It’s possible to enter values and have your UI update in realtime. This is something that’s not possible with the other value input methods.
Anyway. Maybe the UISlider I made can be improved? In the spirit of fairness, openness, and transparency I present the Xcode project I used to do these tests. It needs iOS5. The UIAccurateSlider subclass is in there. It’s totally not production ready so don’t laugh at it too hard. I’ll have a more polished version out very soon.
Thoughts? Leave ’em in the comments.