MOBILE

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;

@end

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"]],
nil
];

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.

Other  
  •  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
  •  jQuery 1.3 : Modifying table appearance (part 4) - Filtering
  •  jQuery 1.3 : Modifying table appearance (part 3) - Collapsing and expanding sections
  •  jQuery 1.3 : Modifying table appearance (part 2) - Tooltips
  •  
    Most View
    Information Theory
    Apple Store Insider Guide (Part 3)
    Microsoft SQL Server 2008 R2 : Hierarchyid Data Type (part 2) - Modifying the Hierarchy
    SQL Server 2008: Monitoring Resource Governor
    Motorola Xoom 2 - General Tablet Use
    Visual Studio 2010 : Introducing the Visual Studio Extensibility - Building a Visual Studio Package
    Windows Server 2008 : The Discovery Phase - Understanding the Existing Environment
    SQL Server 2008 Command-Line Utilities : The tablediff Command-Line Utility
    Web Security : Attacking AJAX - Intercepting and Modifying Server Responses, Subverting AJAX with Injected Data
    Sharepoint 2007: Upload a File - Upload a File from the Web Interface
    Top 10
    ASP.NET 4 in VB 2010 : The Data Controls - Sorting and Paging the GridView
    Microsoft Content Management Server Development : A Date-Time Picker Placeholder Control (part 2)
    Microsoft Content Management Server Development : A Date-Time Picker Placeholder Control (part 1)
    Microsoft Content Management Server Development : Building SharePoint Web Parts - Configuring the Web Part, Debugging the Web Part
    Windows Server 2008 R2 networking : Planning and Deploying DNS (part 4) - Monitoring and troubleshooting DNS
    Windows Server 2008 R2 networking : Planning and Deploying DNS (part 3) - Setting up DNS zones
    Windows Server 2008 R2 networking : Planning and Deploying DNS (part 2) - Installing the DNS Server role, Configuring DNS Servers
    Windows Server 2008 R2 networking : Planning and Deploying DNS (part 1) - Designing a DNS infrastructure
    Windows Server 2008 R2 networking : Routing and Remote Access
    ADO.NET Programming : Microsoft SQL Server (part 4) - Working with Typed Data Sets