Custom UITableViewCell

August 5, 2008    JSON Programming

Make sure you have JSON Framework installed first.

This is a continuation of More Complex JSON endpoint

The reason why OOP is so powerful is that you can subclass everything to make it work or look just how you want it. The default look of a UITableViewCell is just one line of text. If you want to add some text below it you need to subclass that. So that is what we will do right now.

The first thing we want to do is create a new subclass in your project. You should know how to do this already. File -> New File and select a UITableViewCell subclass. I have named mine ImageCell

Now you can see we have the title in nice big letters and the URL to the image under in in smaller letters and also in grey

I am just going to paste all the code and I have made some comments to show you what I added

First your ImageCell.h should look like

#import 

@interface ImageCell : UITableViewCell {
    // adding the 2 labels we want to show in the cell
    UILabel *titleLabel;
    UILabel *urlLabel;
}

// these are the functions we will create in the .m file

// gets the data from another class
-(void)setData:(NSDictionary *)dict;

// internal function to ease setting up label text
-(UILabel *)newLabelWithPrimaryColor:(UIColor *)primaryColor selectedColor:(UIColor *)selectedColor fontSize:(CGFloat)fontSize bold:(BOOL)bold;

// you should know what this is for by know
@property (nonatomic, retain) UILabel *titleLabel;
@property (nonatomic, retain) UILabel *urlLabel;

@end

There really isn’t any magic going on in the header. So now open up the ImageCell.m file and my contents are as follows.

#import "ImageCell.h"

@implementation ImageCell

// we need to synthesize the two labels
@synthesize titleLabel, urlLabel;

- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {
        // Initialization code

        // we need a view to place our labels on.
        UIView *myContentView = self.contentView;

        /*
         init the title label.
         set the text alignment to align on the left
         add the label to the subview
         release the memory
        */
        self.titleLabel = [self newLabelWithPrimaryColor:[UIColor blackColor] selectedColor:[UIColor whiteColor] fontSize:14.0 bold:YES];
        self.titleLabel.textAlignment = UITextAlignmentLeft; // default
        [myContentView addSubview:self.titleLabel];
        [self.titleLabel release];

        /*
         init the url label. (you will see a difference in the font color and size here!
         set the text alignment to align on the left
         add the label to the subview
         release the memory
         */
        self.urlLabel = [self newLabelWithPrimaryColor:[UIColor blackColor] selectedColor:[UIColor lightGrayColor] fontSize:10.0 bold:NO];
        self.urlLabel.textAlignment = UITextAlignmentLeft; // default
        [myContentView addSubview:self.urlLabel];
        [self.urlLabel release];
    }

    return self;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {

    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}

/*
 this function gets in data from another area in the code
 you can see it takes a NSDictionary object
 it then will set the label text
*/
-(void)setData:(NSDictionary *)dict {
    self.titleLabel.text = [dict objectForKey:@"title"];
    self.urlLabel.text = [dict objectForKey:@"img"];
}

/*
 this function will layout the subviews for the cell
 if the cell is not in editing mode we want to position them
*/
- (void)layoutSubviews {

    [super layoutSubviews];

    // getting the cell size
    CGRect contentRect = self.contentView.bounds;

    // In this example we will never be editing, but this illustrates the appropriate pattern
    if (!self.editing) {

        // get the X pixel spot
        CGFloat boundsX = contentRect.origin.x;
        CGRect frame;

        /*
         Place the title label.
         place the label whatever the current X is plus 10 pixels from the left
         place the label 4 pixels from the top
         make the label 200 pixels wide
         make the label 20 pixels high
        */
        frame = CGRectMake(boundsX + 10, 4, 200, 20);
        self.titleLabel.frame = frame;

        // place the url label
        frame = CGRectMake(boundsX + 10, 28, 200, 14);
        self.urlLabel.frame = frame;
    }
}

/*
 this function was taken from an XML example
 provided by Apple

 I can take no credit in this
*/
- (UILabel *)newLabelWithPrimaryColor:(UIColor *)primaryColor selectedColor:(UIColor *)selectedColor fontSize:(CGFloat)fontSize bold:(BOOL)bold
{
    /*
     Create and configure a label.
     */

    UIFont *font;
    if (bold) {
        font = [UIFont boldSystemFontOfSize:fontSize];
    } else {
        font = [UIFont systemFontOfSize:fontSize];
    }

    /*
     Views are drawn most efficiently when they are opaque and do not have a clear background, so set these defaults.  To show selection properly, however, the views need to be transparent (so that the selection color shows through).  This is handled in setSelected:animated:.
     */
    UILabel *newLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    newLabel.backgroundColor = [UIColor whiteColor];
    newLabel.opaque = YES;
    newLabel.textColor = primaryColor;
    newLabel.highlightedTextColor = selectedColor;
    newLabel.font = font;

    return newLabel;
}

- (void)dealloc {
    // make sure you free the memory
    [titleLabel dealloc];
    [urlLabel dealloc];
    [super dealloc];
}

@end

So now we can save that file and open up RootViewController.m

We need to add in a import

#import "ImageCell.h"

Now go down to the cellForRowAtIndexPath function. Right now we have a UITableViewCell *cell call to init the cell, we need to change that since we are using our new ImageCell class. So replace that line with

ImageCell *cell = (ImageCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];

Also we need to replace the cell = line in the if (cell == nil) if statement

cell = [[[ImageCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];

Now remove the cell.text line and replace it with the following

NSDictionary *itemAtIndex = (NSDictionary *)[self.jsonArray objectAtIndex:indexPath.row];
[cell setData:itemAtIndex];

Now you can build and go and you should get the following

As you can see you now have the title in nice big letters and the URL in smaller gray letters below the title. As always you can grabt he source code here.



comments powered by Disqus