Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Populating a UIPickerView in Swift

DZone 's Guide to

Populating a UIPickerView in Swift

· Java Zone ·
Free Resource

I thought it would be an interesting exercise to add a picker control (which Flex developers will know as a SpinnerList) to my dial based colour picker. The new control has a hard coded list of colours - if one of those colours is selected, it updates the RBG and CMYK dial controls and conversely, when either dial control creates a colour that is a match to the picker, it sets its selected item accordingly.

Rather than extending the UIPickerView, I opted for composition and added an instance my new component, ColorSpinner which is an extended UI control. UIPickerViews require two important properties - a delegate which implements the UIPickerViewDelegate protocol and a data source which implements the UIPickerViewDataSource protocol.

I've made the host component, ColorSpinner, both the data source and the delegate.

Unlike lists in Flex, the UIPickerView doesn't accept a collection, rather it invokes methods on the delegate to get data for particular rows in a data source. So, ColorSpinner has a constant array that contains NamedColor structures:

let colors = [
        NamedColor(name: "Custom", color: UIColor.clearColor()),
        NamedColor(name: "Red", color: UIColor.redColor()),
        NamedColor(name: "Green", color: UIColor.greenColor()),
        NamedColor(name: "Blue", color: UIColor.blueColor()),
        [...]
...and the UIPickerView invokes pickerView() with the titleForRow parameter to populate itself:

func pickerView(pickerView: UIPickerView!, titleForRow row: Int, forComponent component: Int) -> String
    {
        return colors[row].name
    }
When the user makes a selection, pickerView() with didSelectRow is invoked, and I set the ColorSpinner's currentColor is set. The didSet observer on that property invokes sendActionsForControlEvents() so that the main view controller can respond:

func pickerView(pickerView: UIPickerView!, didSelectRow row: Int, inComponent component: Int)
    {
        currentColor = colors[row].color
    }
That observer is also invoked when the controller sets the spinner's colour when one of the dial based pickers is changed. Then, I loop over the array, find any matches and the the UIPickerView's selected index. This is a simple loop that uses the enumerate keyword:

for (index, namedColor) in enumerate(colors)
            {
                if namedColor.color.description == currentColor.description
                {
                    spinner.selectRow(index, inComponent: 0, animated: true)
                }
            }
The three controls (spinner, RGB dial control and CMYK dial control) all work together really well (although the UI is a bit ropey in portrait format and works best in landscape). The animated transition on the UIPickerView is a nice touch which I'll be looking to add to my dial controls soon.

As always, all the source code is available in my GitHub repository.


Topics:

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}