Wednesday, February 18, 2009

Generic Selection List Controller

I've got another generic view controller for use in a Navigation-Based Application. This one is for having the user select one item from a list, like so:

This controller works exactly like the other generic ones I've posted. You create an instance, assign yourself as delegate and implement the delegate protocol, then push it onto the stack. The sole delegate method will be used to inform you of a new selection, if one was made. So, here's an example of creating an instance and putting it on the stack:

            SelectionListViewController *controller = [[SelectionListViewController alloc] init];
controller.delegate = self;
controller.list = myNSArrayWithAllPossibleSelections;
controller.initialSelection = theIndexOfTheCurrentlySelectedItem;
[self.navigationController pushViewController:controller animated:YES];
[controller release];

Then, we just need to implement the:

- (void)rowChosen:(NSInteger)row
{
myObject.selection = row;
[self.tableView reloadData];
}

Everything else is handled for you. Here's the code:

SelectionListViewController.h
//
// SelectionListViewController.h
// iContractor
//
// Created by Jeff LaMarche on 2/18/09.
//

#import <UIKit/UIKit.h>

@protocol SelectionListViewControllerDelegate <NSObject>
@required
- (void)rowChosen:(NSInteger)row;
@end


@interface SelectionListViewController : UITableViewController
{
NSArray *list;
NSIndexPath *lastIndexPath;
NSInteger initialSelection;

id <SelectionListViewControllerDelegate> delegate;
}

@property (nonatomic, retain) NSIndexPath *lastIndexPath;
@property (nonatomic, retain) NSArray *list;
@property NSInteger initialSelection;
@property (nonatomic, assign) id <SelectionListViewControllerDelegate> delegate;
@end



SelectionListViewController.m
//
// SelectionListViewController.m
// iContractor
//
// Created by Jeff LaMarche on 2/18/09.
//

#import "SelectionListViewController.h"

@implementation SelectionListViewController
@synthesize list;
@synthesize lastIndexPath;
@synthesize initialSelection;
@synthesize delegate;
-(IBAction)cancel
{
[self.navigationController popViewControllerAnimated:YES];
}

-(IBAction)save
{
[self.delegate rowChosen:[lastIndexPath row]];
[self.navigationController popViewControllerAnimated:YES];
}

#pragma mark -
- (id)initWithStyle:(UITableViewStyle)style
{
initialSelection = -1;
return self;
}

- (void)viewDidLoad
{
[super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated
{
// Check to see if user has indicated a row to be selected, and set it
if (initialSelection > - 1 && initialSelection < [list count])
{
NSUInteger newIndex[] = {0, initialSelection};
NSIndexPath *newPath = [[NSIndexPath alloc] initWithIndexes:newIndex length:2];
self.lastIndexPath = newPath;
[newPath release];
}


UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc]
initWithTitle:NSLocalizedString(@"Cancel", @"Cancel - for button to cancel changes")
style:UIBarButtonItemStylePlain
target:self
action:@selector(cancel)]
;
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
initWithTitle:NSLocalizedString(@"Save", @"Save - for button to save changes")
style:UIBarButtonItemStylePlain
target:self
action:@selector(save)]
;
self.navigationItem.rightBarButtonItem = saveButton;
[saveButton release];

[super viewWillAppear:animated];
}

- (void)dealloc
{
[list release];
[lastIndexPath release];
[super dealloc];
}

#pragma mark -
#pragma mark Tableview methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [list count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

static NSString *SelectionListCellIdentifier = @"SelectionListCellIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SelectionListCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SelectionListCellIdentifier] autorelease];
}


NSUInteger row = [indexPath row];
NSUInteger oldRow = [lastIndexPath row];
cell.text = [list objectAtIndex:row];
cell.accessoryType = (row == oldRow && lastIndexPath != nil) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;

return cell;
}



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

int newRow = [indexPath row];
int oldRow = [lastIndexPath row];

if (newRow != oldRow)
{
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;

UITableViewCell *oldCell = [tableView cellForRowAtIndexPath: lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;

lastIndexPath = indexPath;
}


[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

@end






6 comments:

Ram said...

Thanks for posting this.

I found that the selection list isn't persisting the table view style, so I modified it as follows:

- (id)initWithStyle:(UITableViewStyle)style
{
if (self = [super initWithStyle:style])
{
initialSelection = -1;
}
return self;
}

Not sure if this is correct, but it renders the table correctly now with the passed in initWithStyle value.

spjwebster said...

I've found that you cannot use this controller if you intend to keep it hanging around, rather than releasing it within the delegate method. The table is not reloaded to take account of any data changes, particularly the initialSelection property.

I've rolled in Ram's change and posted the .h and .m files on gist: http://gist.github.com/68574

vibhor goyal said...

Hi,

Thanks a lot for posting this. Could please help me a a bit by explaining where exactly do I need to implement the rowChosen() method.

Edwin said...

scrub m65 kamagra attorney lawyer body scrub field jacket lovegra marijuana attorney injury lawyer

JeansPilot said...

JeansPilot offers the chance to buy a large variety of men’s and women’s jeans clothing from the world famous Italian Brands.
Online jeans clothing store looks for original fashion clothing sales and clearances of worldwide known designers. We participate in fashion auctions to get the lowest possible price for Top quality Clothes, Shoes and Accessories.
Buy Jeans

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels