A small setback
Most week, most days actually, we stumble across various setbacks & challenges (sometimes at first seemingly insurmountable) in the process of app development. We came across such a challenge recently whilst attempting to build a music player for a new app we were working on for a client.
The music player design we were after was similar to the UISlider component of iOS. The problem came to light when we needed to set a number of marks on the player to show the user where each track of that session started.
Slide, slide but no marks?
We began our research and soon discovered that the UISlider iOS component doesn’t allow you to do this, and sadly the only possible customisation for this component was as follows (extract from Apple docs):
“The most common way to customize the slider’s appearance is to provide custom minimum and maximum value images. These images sit at either end of the slider control and indicate which value that end of the slider represents. For example, a slider used to control volume might display a small speaker with no sound waves emanating from it for the minimum value and display a large speaker with many sound waves emanating from it for the maximum value.
The bar on which the thumb rides is referred to as the slider’s track. Slider controls draw the track using two distinct images, which are customizable. The region between the thumb and the end of the track associated with the slider’s minimum value is drawn using the minimum track image. The region between the thumb and the end of the track associated with the slider’s maximum value is drawn using the maximum track image.
Different track images are used in order to provide context as to which end contains the minimum value. For example, the minimum track image typically contains a blue highlight while the maximum track image contains a white highlight. You can assign different tint colors for all of the standard parts provided by the slider, or you customize the appearance further by assigning different pairs of track images to each of the control states of the slider.
Assigning different images to each state lets you customize the appearance of the slider when it is enabled, disabled, highlighted, and so on. In addition to customizing the track images, you can also customize the appearance of the thumb itself. Like the track images, you can assign different thumb images to each control state of the slider.”
Thanks for that Apple.
Apparently, this customisation didn't help us to set the marks. However, not to be deterred, we put our thinking caps on (the boss recently bought us new ones) and came up with a few solutions.
Not to be deterred...
First off - how about we utilise UIView instead of UISlider? We could set an UIView for the thumb, and two images for the selected side and unselected. With a pan gesture recognizer in the thumb we could move it along the x-axis, allowing us to hide and show the two view behind respectively.
However, this solution required a lot of work and we thought there might be simpler and cleaner solutions.
Or, maybe - use a UISlider and set the marks with CoreGraphics inside fixed height and width images (for selected and unselected sides) and use the method
colorWithPattern to dynamically fill the slider bar. The trick was to not reuse the pattern by setting an UIImage with the slider width.
However, we couldn’t easily change the bar height without pixelating it. Moreover, it wasn’t a clean solution (which is always important).
[self.slider setMinimumTrackTintColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"SelectedSide"]]]; [self.slider setMaximumTrackTintColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"UnselectedSide"]]];
How about… similar to the second solution, but now using
SetMinimumTrackImage: forState: and
SetMaximumTrackImage: forState: methods. However, sadly the image was being stretched whenever we moved the thumb.
Resizable image to the rescue
Finally, we struck gold with a solution very similar to the third idea above. We only needed to set the UIImage as a resizable image with the following method:
At last, the image stayed static while we moved the thumb!
Resizable but reusable?
Of course, for any app developer, once you’ve cracked the code (and not just metaphorically) another problem soon arises. We now had our player resizable but not quite reusable yet! So, we turned it into a reusable component by doing the following:
- We created a subclass of UISlider in order to put all the code together and make it reusable.
- We created some properties to customise some elements of the slider like width and colour of the marks, colour of the selected and unselected sides bar and even the colour of the thumb or the possibility to set an image.
- We created all the process with CoreGraphics; firstly, by setting an inner rectangle frame to draw the lines and the selected and unselected sides bar. We made this by getting the mid y-axis point of that rectangle and drawing a line with rounded line cap and fixed width.
Now the slider is fully reusable. Job done. What’s next?
Where can you find it?
See if for yourself on Github: http://github.com/brightec/JMMarkSlider
Check it out over on CocoaPods: http://www.cocoapods.org/?q=JMMarkSlider
This article was originally written for Brightec by Jose Martinez.