Posts Tagged ‘Custom Cell’

UITableViews are awesome. They allow you to display a variety of information, can be customized extensively, take care of memory management and much much more. Since they only remember what’s currently on screen, getting a basic ToDo list up and running can be quite the challenging task for a rookie coder. In this post I’d like to show you how this can be achieved in just a few steps.

First, let’s get all the ingredients ready…

Basically, we need 3 things:

  1. UITableView to display stuff
  2. Data source array, that contains the stuff we want to display
  3. Dictionary, to keep track of what is checked / unchecked

On top of that, we also need:

  1. UITableViewCell to put inside our UITableView
  2. UILabel inside our UITableViewCell to display some text
  3. UIButton inside our UITableViewCell to check / uncheck this cell
Inside the .h file of the ViewController, containing my UITableView, I add the following code:
@interface TableViewCellDemoViewController : UIViewController {

IBOutlet UITableView *tableView;

NSArray *dataSourceArray;

NSMutableDictionary *checkedDictionary;

}

- (void)checkButtonTapped:(id)sender forCellWithLabel:(NSString *)text;

@property (nonatomic, retain) IBOutlet UITableView *tableView;

@property (nonatomic, retain) NSArray *dataSourceArray;

@property (nonatomic, retain) NSMutableDictionary *checkedDictionary;

@end

Inside the .m file I need to properly create the cells…

- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
	BaseCell *cell = (BaseCell *)[_tableView dequeueReusableCellWithIdentifier:@"BaseCell"];

	if (!cell) {
		cell = [[[NSBundle mainBundle] loadNibNamed:@"BaseCell" owner:self options:nil] lastObject];
	}

	cell.selectionStyle = UITableViewCellSelectionStyleNone;

	cell.cellLabel.backgroundColor = [UIColor clearColor];
	cell.cellLabel.font = [UIFont fontWithName:@"Helvetica" size:17];

	cell.cellLabel.text = [dataSourceArray objectAtIndex:indexPath.row];
	cell.parentViewController = self;

    //let's use the cellLabel.text as key inside our checkedDictionary. IMPORTANT: This only works, if information inside cellLabel.text is unique for every row. If you have the same text twice in your datasourceArray, this will cause to some unexpected behavior.

    NSString *key = cell.cellLabel.text;

    BOOL checked = [[checkedDictionary objectForKey:key]boolValue];

    [cell.checkButton setBackgroundImage:(checked) ? [UIImage imageNamed:@"checked.png"] : [UIImage imageNamed:@"unchecked.png"] forState:UIControlStateNormal];

	return (UITableViewCell *)cell;
}

…and add a method, that will get called, if I tap on the check / uncheck button

- (void)checkButtonTapped:(id)sender forCellWithLabel:(NSString *)text {
    UIButton *button = (UIButton  *)sender;

    //like above, we're using the information inside the label (text) as unique identifier = key
    NSString *key = text;

    BOOL checked = [[checkedDictionary objectForKey:key]boolValue];

    //depending on whether the row has been checked before or not, we write YES / NO to our checkedDictionary
    if (checked) {
       [checkedDictionary setValue:@"NO" forKey:text];
        checked = NO;
    }
    else {
        [checkedDictionary setValue:@"YES" forKey:text];
        checked = YES;
    }

    //finally set the new button background image
    [button setBackgroundImage:(checked) ? [UIImage imageNamed:@"checked.png"] : [UIImage imageNamed:@"unchecked.png"] forState:UIControlStateNormal];
}

Finally, I create an empty user interface for Interface Builder and add a UITableViewCell object to it. I also create a new class, named “BaseCell” and set it as custom class for my UITableViewCell.
After adding a UILabel and UIButton object to my cell, I properly link everything and my BaseCell.h file will look like this:

#import <UIKit/UIKit.h>

@interface BaseCell : UITableViewCell {

    IBOutlet UILabel *cellLabel;
    IBOutlet UIButton *checkButton;
    UIViewController *parentViewController;
}

- (IBAction)checkButtonAction:(id)sender;

@property (assign) IBOutlet UILabel *cellLabel;
@property (assign) IBOutlet UIButton *checkButton;
@property (assign) UIViewController *parentViewController;
@end

Last but not least, the .m file will make a call to “checkButtonTapped” method inside my UITableViewController’s class like this:

- (IBAction)checkButtonAction:(id)sender {
    if (self.parentViewController) { //call method inside TableViewCellDemoViewController and submit the sender object (= button) and the text inside the label. We will use the text as unique identifier (=key) inside our checkedDictionary (also part of TableViewCellDemoViewController class)
        [self.parentViewController performSelector:@selector(checkButtonTapped: forCellWithLabel:) withObject:sender withObject:[self.cellLabel text]];
    }
}

If we break down the steps, our app will basically perform the following tasks:

  1. Set up custom UITableView cells, containing a UILabel and UIButton

  2. If user taps on the button, make a call from BaseCell class to TableViewCellDemoViewController class and submit both the sender button and text inside the UILabel

  3. Use the UILabel text to look up a matching key inside our “checkedDictionary” object

  4. Change background image of the UIButton, depending on whether (3) exists and whether it is YES or NO.

That’s it! In case you haven’t done this before, I’m sure you will be confused now. That’s why I created a demo project, so you can explore the code in more detail. Feel welcome to grab the source here.
Have fun and don’t hesitate to leave a comment :)







An App, you might like:
We recommend…
You might also like…
Get Adobe Flash playerPlugin by wpburn.com wordpress themes