Choices

In my Fightcard application, I had to implement a lot of “picker” screens – screens that essentially let the user select one of a list of options, much as a drop-down does in a conventional GUI. Since the behavior of all these screens was so similar, I opted to create a common ChoiceMenu class. I now present it for your consideration.

Examples

Here are some of the “picker” screens in my application:

Choices! Choices! Choices! Choices!

They all follow the same rules:

  • They’re accessed from a parent screen, which shows the current value of a variable
  • They present all possible choices for that variable, with a checkmark next to the current value
  • When the user selects a new value, the screen is popped off the stack, and the parent controller updates its model and view
  • The user may cancel the selection process by touching the back button
  • Each screen has its own title, and possibly displays a prompt as a section header

Code

Without further ado, here are the header and implementation files for my ChoiceMenu class:

ChoiceMenu.h

//
//  ChoiceMenu.h
//  Fightcard
//
//  Created by Michael Heyeck on 8/31/09.
//

#import <UIKit/UIKit.h>


@class ChoiceMenu;


@protocol ChoiceMenuDelegate

- (void)choiceMenu:(ChoiceMenu*)choiceMenu didEndWithObject:(id)object;

@end


@interface ChoiceMenu : UITableViewController {
	NSString*		prompt;
	NSArray*		choices;

	NSUInteger		selection;
	id<ChoiceMenuDelegate>	delegate;
}

@property (nonatomic, assign) NSUInteger selection;
@property (nonatomic, assign) id<ChoiceMenuDelegate> delegate;

- (id)initWithChoices:(NSArray*)a_choices;
- (id)initWithPrompt:(NSString*)a_prompt forChoices:(NSArray*)a_choices;

@end

ChoiceMenu.m

//
//  ChoiceMenu.m
//  Fightcard
//
//  Created by Michael Heyeck on 8/31/09.
//

#import "ChoiceMenu.h"


@implementation ChoiceMenu

- (NSUInteger)selection
{
	return selection;
}

- (void)setSelection:(NSUInteger)a_selection
{
	selection = a_selection;
	[[self tableView] reloadData];
	[[self tableView] scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:selection inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:NO];
}

@synthesize delegate;


// New D. I.(s)
- (id)initWithChoices:(NSArray*)a_choices
{
	return (self = [self initWithPrompt:nil forChoices:a_choices]);
}


- (id)initWithPrompt:(NSString*)a_prompt forChoices:(NSArray*)a_choices
{
	if (self = [super initWithStyle:UITableViewStyleGrouped])
	{
		prompt		= [a_prompt retain];
		choices		= [a_choices retain];
		
		selection	= -1;
	}
	return self;
}


// Super's D. I.
- (id)initWithStyle:(UITableViewStyle)style
{
	return (self = [self initWithChoices:nil]);
}


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
	[super viewDidLoad];

	// Needed to make scrollToRowAtIndexPath:atScrollPosition:animated: work properly near table edges
	static const NSUInteger navBarHeight = 44;
	CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
	self.tableView.frame = CGRectMake(0, navBarHeight, appFrame.size.width, appFrame.size.height-navBarHeight);
}


/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	// Return YES for supported orientations
	return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
	[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
	// Release anything that's not essential, such as cached data
}


- (void)dealloc
{
	[prompt release];
	[choices release];
	[super dealloc];
}

#pragma mark UITableViewDataSource methods

- (NSString*)tableView:(UITableView*)tv titleForHeaderInSection:(NSInteger)section
{
	return prompt;
}


- (NSInteger)tableView:(UITableView*)tv numberOfRowsInSection:(NSInteger)section
{
	return [choices count];
}


- (UITableViewCell*)tableView:(UITableView*)tv cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
	static NSString* cellId = @"CellId";

	UITableViewCell* cell = [tv dequeueReusableCellWithIdentifier:cellId];
	if (cell == nil)
	{
        	cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, 300, 44) reuseIdentifier:cellId] autorelease];
		cell.font = [UIFont systemFontOfSize:18];
	}

	cell.text = [NSString stringWithFormat:@"%@",[choices objectAtIndex:indexPath.row]];
	cell.accessoryType = (selection==indexPath.row)?UITableViewCellAccessoryCheckmark:UITableViewCellAccessoryNone;

	return cell;
}

#pragma mark UITableViewDelegate methods

- (void)tableView:(UITableView*)tv didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
	[tv deselectRowAtIndexPath:indexPath animated:NO];
	if (selection != indexPath.row)
	{
		// Uncheck old row
		[tv cellForRowAtIndexPath:[NSIndexPath indexPathForRow:selection inSection:0]].accessoryType = UITableViewCellAccessoryNone;
		
		// Check new row
		[tv cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
		
		// Update model
		selection = indexPath.row;

		// Invoke delegate method
		[delegate choiceMenu:self didEndWithObject:[choices objectAtIndex:selection]];
	}
}

@end
Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • Reddit
  • HackerNews
  • del.icio.us
  • Google Bookmarks
  • Slashdot
This entry was posted in iPhone. Bookmark the permalink.

Comments are closed.