Picker Views
The UIPickerView class allows users to "spin" a wheel-type control to select one or more values. Each picker view consists of one or more components consisting of one or more rows. Each component can be spun independently of the others. Figure 4.22 shows the picker view being used to select a date value. There are three components in the control, representing the month, day, and year.
Figure 4.22 A picker view being used to select a date.
The number of components and rows in a picker view is determined by its datasource, an object that adopts the UIPickerViewDataSource protocol. The display and selection of the picker view content is handled by the delegate, which adopts the UIPickerViewDelegate protocol (the datasource and the delegate can be the same object).
To create a simple picker view:
- Add the protocol declarations to your interface definition:
@interface UITestViewController : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
Create a picker view, and add it to the main view (Code Listing 4.19):
CGRect pickerFrame = CGRectMake(0,120,0,0); UIPickerView *myPicker = [[UIPickerView alloc] initWithFrame:pickerFrame]; myPicker.dataSource = self; myPicker.delegate = self; [self.view addSubview:myPicker];
Code Listing 4.19 A bare-bones picker view implementation.
Picker views are always 320 pixels by 216 pixels in size and cannot be resized.
- The showsSelectionIndicator property creates a translucent bar across the control to indicate the selected row.
At a minimum, you need to implement two data source methods.
numberOfComponentsInPickerView: returns the number of segments or components in the picker view. In this example, you want a single component, so return the value 1.
pickerView:numberOfRowsInComponent: returns the number of rows for each component. Again, ignore the component parameter (since you have only a single component), and return the number of rows.
- Implement the delegate pickerView:titleForRow:forComponent: method, returning an NSString representation of the current row (Figure 4.23):
return [NSString stringWithFormat:@"Row %i",row];
Figure 4.23 The picker view shows the sample data.
The picker view can display much more interesting data than this simple example. Components can be of different widths and, rather than just simple text, can actually have entire views embedded within them (Figure 4.24).
Figure 4.24 The updated picker view. Not only do the two components display different content, but they also have different widths and numbers of items.
To enhance the picker view:
After calling the initComp1 and initComp2 methods to create some sample data, update the numberOfComponentsInPickerView: method to return two components (one for each of the sample arrays). Also, update the pickerView:numberofRowsInComponent: method to return the size of each array:
if (component == 0) return [comp1 count]; else return [comp2 count];
The arrays here contain different numbers of elements; in other words, components do not need the same number of rows.
- Define a new delegate method, pickerView:widthFormComponent:, and set the widths of the components to different values:
if (component == 0) return 100.0; else return 200.0;
- Implement the pickerView:viewForRow:forComponent:reusingView: delegate, returning either an image view or a label. This method allows you to embed almost any view subclass in a picker view component.
- Finally, in the pickerView:didSelectRow:inComponent: delegate, log the selected row and component to the console. When you spin the picker view, this method isn't fired until the scrolling animation ends. Code Listings 4.20 show the updated code.
Code Listing 4.20 The updated picker view.