Scrubbing through a video with a slider can be difficult. The longer the video is, the less accurate the scrubbing will be. Selecting a specific moment in the video can get fiddly and frustrating.
There’s a nice solution to this, rather hidden in iOS’ video player component
AVPlayerViewController. When you slide your finger up and away from the slider, the rate at which the time changes reduces. The further away you are, the slower it gets.
Frame Grabber is all about picking the right moment, down to the exact frame. It’s the perfect fit for this behavior and I just shipped it in an update. Selecting frames is now a lot easier.
In this post, I’ll outline how to implement this interaction. The result is
ScrubbingSlider, a drop-in
UISlider subclass that adds variable scrubbing speeds.
You can find the full implementation here including a small sample project.
Related Work: Ole Begemann wrote about a similar solution a looong time ago. Check it out here.
Let’s work backwards from how we’re going to use this class to how it is implemented.
ScrubbingSlider exposes two new properties. One configures the discrete speeds the slider uses and the other one returns the current speed:
A scrubbing speed is made up of two parts:
- The fraction of the normal
UISliderspeed to use. 1 is normal speed, 0.5 is half that speed and so on.
- The vertical distance the user’s finger has to move away from the slider for it to take effect.
The slider’s default configuration matches that of
The class is designed as a drop-in replacement for
UISlider without additional setup. In a view controller:
We use the
valueChanged event to check for both the current value and the current scrubbing speed. Since the speed is always tied to a scrub interaction, there is no need to implement a separate update mechanism such as delegation.
As soon as the user touches the slider’s knob, we want to hook in and customize what happens. Our extension points are therefore the slider’s touch handlers. For subclasses of
UISlider), these are:
Three of those are simple: In
beginTracking, we cache the current value as we need it later. In
endTracking, we set the current scrubbing speed back to its default value.
The meat of the work is in
continueTracking, called repeatedly when the user moves her finger. Each time it is called, we want to update two things:
- The current speed
- The current value (adjusted by the current speed)
The following schematic demonstrates what we need to calculate:
One thing I haven’t explained yet is the role of
thumbAdjustment. Notice how in a normal
UISlider, the user’s finger is always right above the knob in a straight line. That’s not the case in
ScrubbingSlider. Due to variable speeds, the finger can be to the left or right of the knob.
What we now want is this: When the user’s finger moves back down towards the slider, the knob rushes towards it so both meet at the same spot. The closer the finger is to the slider, the faster the knob moves. Schematically:
This adjustment value is added to create the slider’s final value.
Finally, we generate a haptic feedback when:
- the current speed changes
- the user hits the start or the end of the slider.
This helps the user feel connected to her interaction with the slider.
For all details, please check out the full implementation.
On its own, this interaction is not very discoverable to the average user. The haptic feedback gives a good indication that something is happening but it’s not sufficient.
AVPlayerViewController implementation shows an explanatory tooltip but only when the user long presses on the slider without moving the finger.
In Frame Grabber, I opted to show an indicator when the user changes speed for the first time during an interaction. After that, it is shown for the remaining interaction. In direct tests with users it was very likely for them to discover it. Users often hit the first speed boundary just by sliding normally. From there, haptic feedback and the speed indicator should do the rest. Making it even more explicit would probably start to annoy the user.
The subclass inherits all built-in accessibility capabilities of
UISlider and is fully functional in that regard. What’s left to do is to expose the different scrubbing speeds to accessibility users.