Tuesday, April 28, 2009

iPhone Development: Custom Cells

Ohhk, quite a lot of things done but this one is something which I have used most often. Custom cells can sometimes greatly push ahead the usability of the application. In this post I am going to create a test project which will demonstrate how to create custom cells and use them appropriately to provide better usability. The application will finally look like this:


So to start open xcode and create a new project, chose the template as "Navigation Based" and  name it as "CustomCellTestProject". What template you chose does not matter, refer my previous posts to find how you can start working on any template.
First thing we will do is create a customCell. Right click on Classes and add a new UITableViewCell subclass. Name it as "CustomCell". Now open CustomCell.h and add the following code:

#import


@interface CustomCell : UITableViewCell {

UILabel *primaryLabel;

UILabel *secondaryLabel;

UIImageView *myImageView;


}

@property(nonatomic,retain)UILabel *primaryLabel;

@property(nonatomic,retain)UILabel *secondaryLabel;

@property(nonatomic,retain)UIImageView *myImageView;

@end


Here we have simply added a primary label to display the primary text, a secondary label and an imageView. These elements will be created and added into the content view of our custom cell. So open CustomCell.m and add the following code

- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {

    if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]) {

        // Initialization code

primaryLabel = [[UILabel alloc]init];

primaryLabel.textAlignment = UITextAlignmentLeft;

primaryLabel.font = [UIFont systemFontOfSize:14];

secondaryLabel = [[UILabel alloc]init];

secondaryLabel.textAlignment = UITextAlignmentLeft;

secondaryLabel.font = [UIFont systemFontOfSize:8];

myImageView = [[UIImageView alloc]init];

[self.contentView addSubview:primaryLabel];

[self.contentView addSubview:secondaryLabel];

[self.contentView addSubview:myImageView];

    }

    return self;

}


We create the three elements and added them to the contentView of our cell. Also don't forget to synthesize all the three elements as we are going to access these elements from other classes.

@synthesize primaryLabel,secondaryLabel,myImageView;


Now, we have already added the UI elements into our cell but you must have noticed, we have not yet defined how these elements will appear inside cell. Go ahead and add the following code for that:

- (void)layoutSubviews {

     [super layoutSubviews];

CGRect contentRect = self.contentView.bounds;

CGFloat boundsX = contentRect.origin.x;

CGRect frame;


frame= CGRectMake(boundsX+10 ,0, 50, 50);

myImageView.frame = frame;

frame= CGRectMake(boundsX+70 ,5, 200, 25);

primaryLabel.frame = frame;

frame= CGRectMake(boundsX+70 ,30, 100, 15);

secondaryLabel.frame = frame;


}


You can do anything in this method to define the lay out of cell. I have simply assigned frames to all the elements.
You can also find a method in CustomCell.m

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


    [super setSelected:selected animated:animated];


    // Configure the view for the selected state

}


This method can be used to define how your cell should react when it is selected. You can describe what should be the highlight color or may be you want to flash one of the labels anything of your choice. I am leaving this method as it is.

We are done with creating our custom cell and now we have to use it. Open RootViewController.m and import CustomCell.h at the top.


#import "CustomCell.h"


I am going to create 5 cells here, you can just use your own logic of specifying number of cells and data. So change the following method to look like this:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return 5;

}


Now we are going to use our custom cell. If you look at the cellForRow method, you will find that a UItableViewCell has been created and re used. Now all we have to do is to replace this cell with our new cell. Change the code inside this method to look like this: 

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

    

    static NSString *CellIdentifier = @"Cell";

    

    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {

        cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];

    }

    

    // Set up the cell...

switch (indexPath.row) {

case 0:

cell.primaryLabel.text = @"Meeting on iPhone Development";

cell.secondaryLabel.text = @"Sat 10:30";

cell.myImageView.image = [UIImage imageNamed:@"meeting_color.png"];

break;

case 1:

cell.primaryLabel.text = @"Call With Client";

cell.secondaryLabel.text = @"Planned";

cell.myImageView.image = [UIImage imageNamed:@"call_color.png"];

break;

case 2:

cell.primaryLabel.text = @"Appointment with Joey";

cell.secondaryLabel.text = @"2 Hours";

cell.myImageView.image = [UIImage imageNamed:@"calendar_color.png"];

break;

case 3:

cell.primaryLabel.text = @"Call With Client";

cell.secondaryLabel.text = @"Planned";

cell.myImageView.image = [UIImage imageNamed:@"call_color.png"];

break;

case 4:

cell.primaryLabel.text = @"Appointment with Joey";

cell.secondaryLabel.text = @"2 Hours";

cell.myImageView.image = [UIImage imageNamed:@"calendar_color.png"];

break;

default:

break;

}

    return cell;

}


I have added some dummy data. You can use your data source to provide data for primaryLabel and secondaryLabel. Please note that I have used three images here. You can use any image of your choice. All you need to to do is copy the images and paste it into your project root folder (which in this case is CustomCellTestProject folder). After pasting the files, in xcode right click on Resources (or any group), select Add >> ExistingFiles and then select all the images you want to add in you project. Once added you can simply use them by their names.

Thats it, go ahead and run the project. You will find something wrong when you compare you simulator screen with mine. If you noticed in the CustomCell.m, I have given some frames to the UI elements. You need to make sure that the height of your cell large enough to accomodate all the elements. So add this following code and you fixed the issue:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

return 50;

}


Let me know if I have been missing something here.




 
 

5 comments:

  1. [self.contentView addSubview:primaryLabel]; gives an error 'contentview in something not a structure or union.
    Thanks for example, I'm still learning, can assist.
    Thanks, pierresinne@gmail.com

    ReplyDelete
  2. i also get the "contentview in something not a structure or union" error. Please advise.

    ReplyDelete
  3. Make sure you are creating a separate class CustomCell and putting the code in there and UITableView code in RootViewController.m

    ReplyDelete
  4. ryt...you might not have implemented the CustomCell

    ReplyDelete
  5. what size does my image have to be for it to work?

    ReplyDelete

Leave your suggestions