Sau93 Sau93 - 1 year ago 60
iOS Question

How I can make a custom UITableViewCell with 2 label so if the text of a label is empty the other fills the space?


Text in textLabel and descriptionLabel isn't empty
enter image description here

Text descriptionLabel is empty

enter image description here

It's possible con Autolayout or it's necessary to override some method.

Answer Source

If it's a custom label, the easy fix here is to just use one label and add either 1 or 2 lines of attributed text. I just threw a project together and it works OK. I've put more explanation than you'll need (you already know how to subclass a table view cell, but for people who might need it, I've added a lot of detail). Basically:

  1. Subclass UITableViewCell and add a single label. Set your auto layout so the label is aligned vertically in the cell and set your left and right margins. You'll probably have to mess with auto layout to add padding to the top or bottom, but I'll leave the wrestling with auto layout to you lol

  2. Create either 1 or 2 NSMutableAttributedStrings. If you have only 1 string, it will center in the label on one line, with auto layout fitting around the text. If you have two lines, just add a return character.

Note: This code assumes you will always have at least the title, with the subtitle being optional.

Here is the tableViewController.m code I used

#import "MyTableViewController.h"
#import "CustomCell.h"

@implementation MyTableViewController

- (void)viewDidLoad 
    [super viewDidLoad];

    //1. Register custom nib
    [self.tableView registerNib:[UINib nibWithNibName:[CustomCell nibName] bundle:nil] forCellReuseIdentifier:[CustomCell resuseIdentifier]];

    //2. Set a suggested height for auto-layout
    self.tableView.estimatedRowHeight = 45;

#pragma mark - UITableView datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    return 1; 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    return 2; 

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

    //1. Create an instance of the custom cell
    CustomCell *cell = (CustomCell*)[self.tableView dequeueReusableCellWithIdentifier:[CustomCell resuseIdentifier] forIndexPath:indexPath];

    //2. Setting some filler text (this would come from your data object)
    if (indexPath.row == 0) {
    cell.title = @"A cell with only title text";
    } else {
    cell.title = @"First we have the title";
    cell.subTitle = @"And here is the subtitle";

    return cell;

And this is the .h and .m for the custom UITableViewCell. Remember to subclass your prototype cell in storyboard to this class.

//  CustomCell.h

#import <UIKit/UIKit.h>

@interface CustomCell : UITableViewCell

+ (NSString *)nibName;
+ (NSString *)resuseIdentifier;

@property (strong, nonatomic) NSString *title;
@property (strong, nonatomic) NSString *subTitle;


And finally the CustomCell.m. It's long, so you'll have to scroll through. Sorry about that.

//  CustomCell.m
#import "CustomCell.h"

//1. Created a typeDef to identify which label we are dealing with
typedef NS_ENUM(NSInteger, CustomLabelType) {
    CustomLabelTypeTitle = 0,

@interface CustomCell()

//IBOutlet to custom .xib file of UITableViewCell file
@property (weak, nonatomic) IBOutlet UILabel *customLabel;


@implementation CustomCell

+ (NSString *)nibName
    return @"CustomCell";

+ (NSString *)resuseIdentifier
    return @"CustomCellReuseIdentifier";

- (void)setTitle:(NSString *)title
    _title = title;

- (void)setSubTitle:(NSString *)subTitle
    _subTitle = subTitle;

- (void)setSelected:(BOOL)selected animated:(BOOL)animated 
    [super setSelected:selected animated:animated];

    //1. Add a line return after the title if we have a subtitle
    if (self.subTitle) {
    self.title = [NSString stringWithFormat:@"%@%@",self.title, @"\n"];

    //2. Set the title to allow for 2 lines of text
    self.customLabel.numberOfLines = 2;

    NSMutableAttributedString *attTitle;
    NSMutableAttributedString *attSubTitle;

    //3. Set the title
    if (self.title)
    attTitle = [self _mutableStringWithText:self.title type:CustomLabelTypeTitle];

    //4. If we have a subtitle, append it to the title attributed string
    if (self.title && self.subTitle) {
    attSubTitle = [self _mutableStringWithText:self.subTitle type:CustomLabelTypeSubtitle];
    [attTitle appendAttributedString:attSubTitle];

    //5. Set your label
    [self.customLabel setAttributedText:attTitle];


- (NSMutableAttributedString *)_mutableStringWithText:(NSString *)labelText type:(CustomLabelType)labelType
    //1. Create attributes for title vs subtitle
    UIFont *labelFont = [UIFont systemFontOfSize: (labelType == CustomLabelTypeTitle) ? 16 : 12];
    UIColor *textColor = (labelType == CustomLabelTypeTitle) ? [UIColor blackColor] : [UIColor grayColor];

    //2. Create the paragraph style you want, including line spacing
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    [paragraphStyle setLineSpacing:6.5];
    paragraphStyle.alignment = NSTextAlignmentLeft;

    //3. Create your attributes dictionary
    NSDictionary *paragraphAttributes = @{NSParagraphStyleAttributeName: paragraphStyle, NSFontAttributeName: labelFont, NSForegroundColorAttributeName:textColor};

    //4. Create and return your string
    NSMutableAttributedString *mutableString = [[NSMutableAttributedString alloc] initWithString:labelText attributes:paragraphAttributes];

    return mutableString;