The need for custom controls
If you ever implemented an iOS app customizing standard control elements, you may know how hard it may be at times to get a standard control look like that masterpiece your designer drew out meticulously. We do a lot of custom-designed apps here at Inexika, and we'd love to share some code & tricks that you would hopefully take advantage of. We'll publish several case studies in a series of small blog posts, and this is the first one.
Here we will show how to customize a background texture, selection indicator (glass), and even the subtlest aspects of how selection wheels look in UIPickerView & UIDatePicker controls.
We have first come to changing the appearance of UIPickerView while working on a custom-designed app for one of our clients. We needed a picker that would have custom background texture and selection glass.
As there were no dynamic elements that would change at runtime, we chose the simplest way to do the job — by overlaying the picker with an image that contained a frame and the glass. This approach was good for that situation as all we had to do was prepare the image and drop it upon the picker in xib file. If you have a graphics designer at hand you should be happy with this approach up until the moment you realize you need a custom look for a picker that may change its appearance (in particular, the number and dimensions of selection wheels) at runtime, such as UIDatePicker which changes depending on your current date/time format. In our new product iMood Diary, our senior iOS developer Vadim implemented a clever picker overlay view that enables customization of dynamically defined UIPickerView objects & UIDatePicker (the latter does not inherit from UIPickerView but instead contains it as a subview). See how our IXPickerOverlayView transforms the look of the control:
Overall appearance of the picker can be changed with just 2 graphic assets:
- the background texture image (can be tiled!), and
- the selection indicator image (usually glass).
You can also change the tint of the wheels and bevels, but that's a bit tricky and not as flexible as you might expect: you or your designer will need to know exactly how view/layer compositing works in order to prepare proper graphical assets.
How it works
IXPickerOverlayView is actually dead simple. You provide it with a reference to a picker view, and it polls picker for the parameters of its wheels (components), then masks out the region corresponding to the wheels using CAShapeLayer. All kinds of overlays are then applied. If IXPickerOverlayView cannot find a UIPickerView instance in its host's hierarchy (just in case Apple changes the implementation of UIDatePicker), it falls back to presenting nothing so that the standard picker view appears in the UI.
IXPickerOverlayView automatically changes with UIDatePicker when locale settings change. If you use custom-configured picker, you need to call setNeedsLayout when you change the number or width of selection wheels — the overlay will catch up.
How to use it?
Hey, it's open source and available under MIT license! Download the latest version of the source code from GitHub. You will find a sample project in the package. To integrate IXPickerOverlayView into your project:
- Drag IXPickerOverlayView folder to your project navigator in Xcode (be sure to copy the resources)
- Link your current target with QuartzCore framework
- Place IXPickerOverlayView instance over your picker view with the same frame as the picker view
- Set IXPickerOverlayView's hostPickerView outlet (be sure not to add the overlay to picker as a subview: this will lead to reference cycle as the outlet is a strong reference)
- If you use a custom-configured picker, be sure to call setNeedsLayout on corresponding IXPickerOverlayView instance once you change the number or width of selection wheels.
- Replace ixPickerOverlayTexture & ixPickerOverlayGlass images to give the control its desired appearance.
More nice & tidy pieces of a code to come. Stay tuned!