Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom UITableViewCell programmatically using AutoLayout

I'm trying to implement a UITableView that will behave similarly to the timeline of a twitter client. Right now I'm simply attempting to get two labels inside a UITableViewCell. As recommended by this Stack Overflow answer, I'm using a different reuseIdentifier for each layouts. My layouts are simple, consisting of either a single label or two labels. Eventually I will be adjusting the height of the UITableViewCells but first I need to get the cells populated with content.

I can get the labels so show up if I set their frame with initWithFrame:, however the constraints aren't being implemented.

  • Question: What is preventing the labels and constraints from appearing? I'm clearly missing something in my implementation of the UITableViewCell but I have no idea what it is.

  • Secondary question: Am I registering the UITableViewCell class correctly for each reuseIdentifier in viewDidLoad?

This might come across as being difficult but Interface Builder confuses me, I would like to accomplish this all in code.

Here is the code for the custom UITableViewCell named TVTCell.h:

static NSString * const kCellIDTitle = @"CellWithTitle"; static NSString * const kCellIDTitleMain = @"CellWithTitleMain";  @interface TVTCell : UITableViewCell {     NSString *reuseID; }  @property (nonatomic, strong) UILabel *nameLabel; @property (nonatomic, strong) UILabel *mainLabel;  @end 

And TVTCell.m:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];     if (self) {         reuseID = reuseIdentifier;          nameLabel = [[UILabel alloc] init];         [nameLabel setTextColor:[UIColor blackColor]];         [nameLabel setBackgroundColor:[UIColor colorWithHue:32 saturation:100 brightness:63 alpha:1]];         [nameLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];         [nameLabel setTranslatesAutoresizingMaskIntoConstraints:NO];         [self.contentView addSubview:nameLabel];          mainLabel = [[UILabel alloc] init];         [mainLabel setTextColor:[UIColor blackColor]];         [mainLabel setBackgroundColor:[UIColor colorWithHue:66 saturation:100 brightness:63 alpha:1]];         [mainLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];         [mainLabel setTranslatesAutoresizingMaskIntoConstraints:NO];         [self.contentView addSubview:mainLabel];          [self.contentView setTranslatesAutoresizingMaskIntoConstraints:NO];      }     return self; }   - (void)updateConstraints {     [super updateConstraints];      NSDictionary *views = NSDictionaryOfVariableBindings(nameLabel, mainLabel);     if (reuseID == kCellIDTitle) {         NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"                                                 options: NSLayoutFormatAlignAllCenterX                                                 metrics:nil                                                   views:views];         [self.contentView addConstraints:constraints];         constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel]|"                                                               options: NSLayoutFormatAlignAllCenterX                                                               metrics:nil                                                                 views:views];         [self.contentView addConstraints:constraints];     }     if (reuseID == kCellIDTitleMain) {         NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"                                                                        options: NSLayoutFormatAlignAllCenterX                                                                        metrics:nil                                                                          views:views];         [self.contentView addConstraints:constraints];          constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mainLabel]|"                                                                        options: NSLayoutFormatAlignAllCenterX                                                                        metrics:nil                                                                          views:views];         [self.contentView addConstraints:constraints];          constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel][mainLabel]|"                                                               options: NSLayoutFormatAlignAllLeft                                                               metrics:nil                                                                 views:views];         [self.contentView addConstraints:constraints];          [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:nameLabel                                      attribute:NSLayoutAttributeHeight                                      relatedBy:NSLayoutRelationEqual                                         toItem:nil                                      attribute:NSLayoutAttributeNotAnAttribute                                     multiplier:0.0                                       constant:44.0]];         [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:nameLabel                                                                      attribute:NSLayoutAttributeWidth                                                                      relatedBy:NSLayoutRelationEqual                                                                         toItem:self.contentView                                                                      attribute:NSLayoutAttributeNotAnAttribute                                                                     multiplier:0.0                                                                       constant:1]];     } } 

Sorry, ton of code. Here's my UITableView's tableView:cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {     if (indexPath.row == 0 || indexPath.row == 2 || indexPath.row == 3) {         TVTCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIDTitle forIndexPath:indexPath];          [[cell nameLabel] setText:[nameArray objectAtIndex:indexPath.row]];          return cell;     } else if (indexPath.row == 1 || indexPath.row == 4 || indexPath.row == 5) {         TVTCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellIDTitleMain forIndexPath:indexPath];          [[cell nameLabel] setText:[nameArray objectAtIndex:indexPath.row]];         [[cell mainLabel] setText:[dataArray objectAtIndex:indexPath.row]];          return cell;     } else     {         UITableViewCell *badCell = [[UITableViewCell alloc] init];         NSLog(@"Warning! returning a cell that shouldnt be here");         badCell.textLabel.text = @"Warning!";         return badCell;     } } 

And lastly, the UITableView's viewDidLoad method:

- (void)viewDidLoad {     [super viewDidLoad];      [[self tableView] registerClass:[TVTCell class] forCellReuseIdentifier:kCellIDTitle];     [[self tableView] registerClass:[TVTCell class] forCellReuseIdentifier:kCellIDTitleMain]; } 
like image 949
Shawn Throop Avatar asked Sep 23 '13 21:09

Shawn Throop


People also ask

How do I change the tableView style programmatically in Swift?

You cannot change the tableView style once set. So the only way is set the style during initialisation.

What is UITableView in Swift?

A view that presents data using rows in a single column. iOS 2.0+ iPadOS 2.0+ Mac Catalyst 13.1+ tvOS 9.0+

What is Cellforrowat?

Basically it's designing your cell, The cellforrowatindexpath is called for each cell and the cell number is found by indexpath.row and section number by indexpath.section . Here you can use a label, button or textfied image anything that you want which are updated for all rows in the table.


1 Answers

There are several things wrong with your code. First, I think you'll find, if you do some logging, that updateConstraints is never called. I would put all the code in the init method. Also, there are several things wrong in your constraints. The constraint where you set the height to 44 is not needed since you already have the labels pinned to the to and bottom of the cell. I don't know what you're trying to do with that last one, it looks like that would make the nameLabel 1 point wide. Also, you shouldn't set the translatesAutoresizingMaskIntoConstraints to NO for the content view, that causes weird effects. So this is the code I think you want:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];     if (self) {         reuseID = reuseIdentifier;          nameLabel = [[UILabel alloc] init];         [nameLabel setTextColor:[UIColor blackColor]];         [nameLabel setBackgroundColor:[UIColor colorWithHue:32 saturation:100 brightness:63 alpha:1]];         [nameLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];         [nameLabel setTranslatesAutoresizingMaskIntoConstraints:NO];         [self.contentView addSubview:nameLabel];          mainLabel = [[UILabel alloc] init];         [mainLabel setTextColor:[UIColor blackColor]];         [mainLabel setBackgroundColor:[UIColor colorWithHue:66 saturation:100 brightness:63 alpha:1]];         [mainLabel setFont:[UIFont fontWithName:@"HelveticaNeue" size:18.0f]];         [mainLabel setTranslatesAutoresizingMaskIntoConstraints:NO];         [self.contentView addSubview:mainLabel];          NSDictionary *views = NSDictionaryOfVariableBindings(nameLabel, mainLabel);         if (reuseID == kCellIDTitle) {             NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"                                                                            options: 0                                                                            metrics:nil                                                                              views:views];             [self.contentView addConstraints:constraints];             constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel]|"                                                                   options: 0                                                                   metrics:nil                                                                     views:views];             [self.contentView addConstraints:constraints];         }         if (reuseID == kCellIDTitleMain) {             NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel]|"                                                                            options:0                                                                            metrics:nil                                                                              views:views];             [self.contentView addConstraints:constraints];              constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mainLabel]|"                                                                   options: 0                                                                   metrics:nil                                                                     views:views];             [self.contentView addConstraints:constraints];              constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel][mainLabel(==nameLabel)]|"                                                                   options: 0                                                                   metrics:nil                                                                     views:views];             [self.contentView addConstraints:constraints];          }     }     return self; } 
like image 59
rdelmar Avatar answered Sep 19 '22 20:09

rdelmar