Question

I want to assign a header title for my table view, but I want the title to be in two lines. The second line should have a smaller font than the top line.

I am trying to use NSMutableAttributedString, but in the method:

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section

But it returns a NSString instead of NSMutableAttributedString.

Is there any way that I can convert the NSMutableAttributedString to NSString while keeping the formatting of the string?

Here is my code:

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    NSString *title = @"";
    title = @"Top Line \n";
    if(_favouriteLocations.count == 0){
        title = [title stringByAppendingString:@"Smaller font Bottom Line"];
    }
    NSMutableAttributedString *attString =[[NSMutableAttributedString alloc] initWithString:title];
    NSRange range = [title rangeOfString:@"Smaller"];

    [attString setAttributes:@{NSFontAttributeName:@"8"} range:NSMakeRange(range.location, title.length - range.location)];

     NSLog(@"%@", attString);
     title = [attString string];

     return title;
}
Was it helpful?

Solution

There is no way of doing this using the tableView:titleForHeaderInSection: method. You need to use tableView:viewForHeaderInSection: which is a UITableViewDelegate method and return a UILabel with the attributedText set

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    NSString *title = @"";
    title = @"Top Line \n";
    if(_favouriteLocations.count == 0){
        title = [title stringByAppendingString:@"Smaller font Bottom Line"];
    }
    NSMutableAttributedString *attString =[[NSMutableAttributedString alloc] initWithString:title];
    NSRange range = [title rangeOfString:@"Smaller"];

    [attString setAttributes:@{NSFontAttributeName:@"8"} range:NSMakeRange(range.location, title.length - range.location)];

     UILabel *titleLabel = [UILabel new];
     titleLabel.attributedText = attString;

     return titleLabel;
}

If you've got a lot of sections you could also use the newer UITableViewHeaderFooterView class and dequeue that. That view has a textLabel property and just like above you could set the attributedText on that. Its a bit more code but more efficient as you then don't return a newly created view each time.

static NSString *const HeaderCellId = @"header_id";

-(void)viewDidLoad
{
    [super viewDidLoad];

    // Setup table view
    [tableView registerClass:[UITableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:HeaderCellId];
}

-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {

    NSString *title = @"";
    title = @"Top Line \n";
    if(_favouriteLocations.count == 0){
        title = [title stringByAppendingString:@"Smaller font Bottom Line"];
    }
    NSMutableAttributedString *attString =[[NSMutableAttributedString alloc] initWithString:title];
    NSRange range = [title rangeOfString:@"Smaller"];

    [attString setAttributes:@{NSFontAttributeName:@"8"} range:NSMakeRange(range.location, title.length - range.location)];

    UITableViewHeaderFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:HeaderCellId];

    view.textLabel.attributedText = attString;

    return view;
}

EDIT:

As noted by @PabloRomeu in the comments tableView:viewForHeaderInSection: only works if tableView:heightForHeaderInSection: is implemented returning a non-zero value.

-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 80;
}

OTHER TIPS

Implement this tableview delegate method,

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

And return a UILabel with a AttributedString set to it's text value

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top