iPhone Application Development : Implementing a Custom Picker View (part 4) - Tweaking the Picker UI

2/27/2011 10:21:55 AM

Tweaking the Picker UI

Once you’ve got a working picker view, you can start using some of the optional UIPickerViewDelegate methods to dramatically alter its appearance. We’ll change the picker to display icons of the animals rather than the animal names.

Adding the Image Resources and Data

I’ve supplied seven animal image PNG files inside the Animals folder of the MatchPicker project folder. Start by finding and dragging the image files into the Resources folder of your project in Xcode. When prompted, choose to copy the items if needed, as shown in Figure 8.

Figure 8. Copy the images to the project if needed.

The UIPickerView can display any UIView or subclass of UIView within its components. To display an image, we’ll need to add it to a view and make it available to the picker. Despite this sounding a bit daunting, we can create a new UIImageView instance and populate it with an image from our project resources using a single line:

[[UIImageView alloc] initWithImage:[UIImage imageNamed:<image name>]]

So, what do we do with these UIImageViews once we create them? The same thing we did with the animal names and animal sounds—we put them in an array. That way, we can simply pass the appropriate image view to the picker in the exact same way we were passing strings!

By the Way

Remember, if you want to address the ultra-high resolution display of the iPhone 4, you can add image resources with twice the vertical and horizontal resolution and a suffix of @2x to your projects. They’ll automatically be displayed without any additional coding!

Start by updating the MatchPickerViewController.h file to declare an NSArray called animalImages. The final (for real!) interface file is displayed in Listing 7.

Listing 7.
#import <UIKit/UIKit.h>

@interface MatchPickerViewController : UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate> {
NSArray *animalNames;
NSArray *animalSounds;
NSArray *animalImages;
IBOutlet UILabel *lastAction;
IBOutlet UILabel *matchResult;
@property (nonatomic, retain) UILabel *lastAction;
@property (nonatomic, retain) UILabel *matchResult;


Edit the viewDidLoad method within MatchPickerViewController.m to include the code to populate an array with seven image views corresponding to our animal PNG files. This code should be added following the allocation and initialization of the animalSounds or animalNames arrays:

animalImages=[[NSArray alloc]initWithObjects:
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"mouse.png"]],
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"goose.png"]],
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cat.png"]],
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dog.png"]],
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"snake.png"]],
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bear.png"]],
[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pig.png"]],

Next, update the dealloc method to release this new array when the application is finished with it:

- (void)dealloc {
[animalNames release];
[animalSounds release];
[animalImages release];
[lastAction release];
[matchResult release];
[super dealloc];

Using Views (with Images!) in a Picker View

Wouldn’t it be great if we could just provide the image view to the picker in place of the animal name string in pickerView:titleForRow:forComponent and have it work? Guess what. It won’t. Unfortunately, pickers operate in only one of two ways—either by displaying strings using the aforementioned method or displaying custom views using the method pickerView:viewForRow:forComponent:reusingView—but not a combination.

What this means for us is that if we want to display image views in the picker, everything else we want to show will have to be a subclass of UIView as well. The animal sounds are strings, so to display them, we need to create something that is a subclass of UIView that contains the necessary text. That “something” is a UILabel. By creating UILabels from the strings in the animalSounds array, we can successfully populate the picker with both images and text.

Begin by commenting out the pickerView:titleForRow:forComponent in MatchPickerViewController.m, by placing /* before the start, and */ after the end of the method. Alternatively, you can just delete the entire method (because we won’t really need it again in this project).

Now, enter the following implementation of pickerView:viewForRow:forComponent:reusingView from Listing 8.

Listing 8.
 1: - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row
2: forComponent:(NSInteger)component reusingView:(UIView *)view {
3: if (component==animalComponent) {
4: return [animalImages objectAtIndex:row];
5: } else {
6: UILabel *soundLabel;
7: soundLabel=[[UILabel alloc] initWithFrame:CGRectMake(0,0,100,32)];
8: [soundLabel autorelease];
9: soundLabel.backgroundColor=[UIColor clearColor];
10: soundLabel.text=[animalSounds objectAtIndex:row];
11: return soundLabel;
12: }
13: }

In lines 3–4, we check to see whether the component requested is the animal component, and if it is, we use the row parameter to return the appropriate UIImageView stored in the animalImages array. This is nearly identical to how we dealt with the strings earlier.

If the component parameter isn’t referring to the animal component, then we need to return a UILabel with the appropriate referenced row from the animalSounds array. This is handled in lines 6–11.

In line 6, we declare a UILabel named soundLabel.

Line 7 allocates and initializes soundLabel with a frame using the initWithFrame method. Remember from earlier hours that views define a rectangular area for the content that is displayed on the iPhone screen. To create the label, we need to define the rectangle of its frame. The CGRectMake function takes starting x,y values and ending x,y values to define the height and width of a rectangle. In this example, we’ve defined a rectangle that spans 0 to 100 points horizontally and 0 to 32 points vertically.

Line 8 calls autorelease on the soundLabel object. This is a bit different from what we’ve done elsewhere. Why can’t we just release soundLabel at the end of the method like everything else? The answer is that we have to return soundLabel so the picker can use it—so we can’t just get rid of it. By using autorelease, we can hand off the object to the picker and relieve ourselves of the responsibility of releasing it.

Line 9 sets the background color attribute of the label to be transparent. As you learned with web views, [UIColor clearColor] returns a color object configured as transparent. If we leave this line out, the rectangle will not blend in with the background of the picker view.

Line 10 sets the text of the label to the string in of the specified row in animalSounds.

Finally, line 11 returns the UILabel—ready for display.

You can use Build and Run to run the application, but there’s still going to be a slight issue: The rows aren’t quite the right size to accommodate the images.

Changing Row Sizes

To control the width and height of the rows in the picker components, two additional delegate methods can be implemented:

pickerView:rowHeightForComponent: Given a component number, this method should return the height, in points, of the row being displayed.

pickerView:widthForComponent: Given a component number, this method returns the width of that component, in points.

For this sample application, some trial and error led me to determine that the animal component should be 75 points wide, while the sound component looks best at around 150 points.

Both components should use a constant row height of 55 points.

Translating this into code, implement pickerView:rowHeightForComponent as follows:

- (CGFloat)pickerView:(UIPickerView *)pickerView
rowHeightForComponent:(NSInteger)component {
return 55.0;

Similarly, pickerView:widthForComponent becomes this:

- (CGFloat)pickerView:(UIPickerView *)pickerView
widthForComponent:(NSInteger)component {
if (component==animalComponent) {
return 75.0;
} else {
return 150.0;

With those small additions to MatchPickerViewController.m, the UIPickerView project is complete! You should now have a good understanding of how to create and customize pickers and how to manage a user’s interaction with them.

  •  iPhone Application Development : Implementing a Custom Picker View (part 3) - Reacting to a Picker View Choice
  •  iPhone Application Development : Implementing a Custom Picker View (part 2)
  •  iPhone Application Development : Implementing a Custom Picker View (part 1)
  •  Windows Phone 7 Development : Isolated Storage - Working with Isolated Storage Settings
  •  Mobile Application Security : WebOS Security - Permissions and User Controls
  •  Mobile Application Security : WebOS Security - Code Security
  •  Windows Phone 7 Development : Working with Isolated Directory Storage (part 2)
  •  Windows Phone 7 Development : Working with Isolated Directory Storage (part 1)
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Using Date Pickers (part 3)
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Using Date Pickers (part 2) - Adding a Date Picker
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Using Date Pickers (part 1)
  •  iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
  •  Sync Your iPad with iTunes : Troubleshooting iTunes and the Sync
  •  Sync Your iPad with iTunes : Manually Transferring Music, Movies, Podcasts, and More on Your iPad (Drag-and-Drop Method)
  •  Windows Phone 7 Development : Internationalization - Using Resource Files to Localize Content
  •  Windows Phone 7 Development : Internationalization - Storing and Retrieving Current Culture Settings
  •  Mobile Application Security : WebOS Security - Development and Security Testing
  •  Mobile Application Security : WebOS Security - Introduction to the Platform
  •  iPhone Application Development : Getting the User’s Attention - Using Alert Sounds and Vibrations
  •  iPhone Application Development : Getting the User’s Attention - Using Action Sheets
    Top 10
    Building Out Of Browser Silverlight Applications - Controlling the Application Window
    Exchange Server 2010 : Maintaining Reliability and Availability - Recover Data
    jQuery 1.3 : Table Manipulation - Sorting and paging (part 1) : Server-side sorting & JavaScript sorting
    jQuery 1.3 : Developing plugins - Adding new global functions
    SQL Server 2008 : Programming Objects - Implementing Stored Procedures
    Windows Azure : Messaging with the queue - Decoupling your system with messaging
    Tools to Manage Access Control Lists
    Mobile Application Security : The Apple iPhone - Local Data Storage: Files, Permissions, and Encryption
    Design and Deploy High Availability for Exchange 2007 : Create Bookmark Create Note or Tag Implement Standby Continuous Replication (SCR)
    Deploying the Client for Microsoft Exchange Server 2010 : Pushing Outlook Client Software with Group Policies
    Most View
    ASP.NET 4 in VB 2010 : The Security Controls
    iPhone 3D Programming : Adding Textures to ModelViewer (part 4) - Enabling Textures with ES2::RenderingEngine
    Outlining AD DS Changes in Windows Server 2008 R2 (part 3) - Auditing Changes Made to AD Objects
    SharePoint 2010 : SQL Server Database Mirroring for SharePoint Farms
    Building LOB Applications : Data Validation through Data Annotation
    Navigating Architecture Changes in Windows Vista
    iPhone 3D Programming : Adding Depth and Realism - Shaders Demystified
    jQuery 1.3 : Modifying table appearance (part 2) - Tooltips
    Design and Deploy High Availability for Exchange 2007 : Design Edge Transport and Unified Messaging High Availability
    Personalizing Windows 7 (part 3) - Choosing and Configuring Your Screensaver
    SQL Server 2008 : Service Broker - Message Types
    Designing and Implementing Mobility in Exchange Server 2010 : Securing Access to ActiveSync Using Internet Security and Acceleration (ISA) Server 2006
    SQL Server 2008 : What Is the Base Class Library?
    Creating and Managing Views in SQL Server 2008 : Creating Views
    Examining Integration Points Between SharePoint and Public Key Infrastructure
    jQuery 1.3 : Modifying table appearance (part 3) - Collapsing and expanding sections
    Advanced ASP.NET : Creating a Component
    Installing SharePoint 2010 Using PowerShell
    iPhone 3D Programming : Holodeck Sample (part 4) - Replacing Buttons with Orientation Sensors
    iPhone 3D Programming : Reflections with Cube Maps