Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UINavigationBar TitleView with subtitle

I want a titleView inside my UINavigationBar which has two lines of text instead of only one

My current implementiation works well when I have a "Back"-Button and an "Edit" Button because it looks nearly centered. The problem is when I only have one of the Buttons. It looks really weird and wrong because the view centers itself on the available space.

UINavigationBar with left and right Button

UINavigationBar with only one Button

This is my current implementation:

CGRect frame = self.navigationController.navigationBar.frame;

UIView *twoLineTitleView = [[UIView alloc] initWithFrame:CGRectMake(CGRectGetWidth(frame), 0, CGRectGetWidth(frame), CGRectGetHeight(frame))];

UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 8, CGRectGetWidth(frame), 14)];
titleLabel.backgroundColor = [UIColor clearColor];
titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
titleLabel.textAlignment = UITextAlignmentCenter;
titleLabel.text = self.title;
[twoLineTitleView addSubview:titleLabel];

UILabel *subTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 23, CGRectGetWidth(frame), 14)];
subTitleLabel.backgroundColor = [UIColor clearColor];
subTitleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
subTitleLabel.textAlignment = UITextAlignmentCenter;
subTitleLabel.text = self.subTitle;
[twoLineTitleView addSubview:subTitleLabel];

self.navigationItem.titleView = twoLineTitleView;
like image 456
Stefan Edler Avatar asked Oct 16 '12 11:10

Stefan Edler


3 Answers

Here is how I would do it:

  • Use sizeToFit for each of your two labels.
  • Have the container view's width set to the max width of your two labels.
  • Center the smaller of the two labels on the view.

This code should work for you:

    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
    titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.textColor = [UIColor whiteColor];
    titleLabel.font = [UIFont boldSystemFontOfSize:20];
    titleLabel.text = @"Your Title";
    [titleLabel sizeToFit];

    UILabel *subTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 22, 0, 0)];
    subTitleLabel.backgroundColor = [UIColor clearColor];
    subTitleLabel.textColor = [UIColor whiteColor];
    subTitleLabel.font = [UIFont systemFontOfSize:12];
    subTitleLabel.text = @"Your subtitle";
    [subTitleLabel sizeToFit];

    UIView *twoLineTitleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, MAX(subTitleLabel.frame.size.width, titleLabel.frame.size.width), 30)];
    [twoLineTitleView addSubview:titleLabel];
    [twoLineTitleView addSubview:subTitleLabel];

    float widthDiff = subTitleLabel.frame.size.width - titleLabel.frame.size.width;

    if (widthDiff > 0) {
        CGRect frame = titleLabel.frame;
        frame.origin.x = widthDiff / 2;
        titleLabel.frame = CGRectIntegral(frame);
    }else{
        CGRect frame = subTitleLabel.frame;
        frame.origin.x = abs(widthDiff) / 2;
        subTitleLabel.frame = CGRectIntegral(frame);
    }

    self.navigationItem.titleView = twoLineTitleView;

Swift 3 variant:

    let titleLabel = UILabel.init(frame: CGRect.zero)
    titleLabel.backgroundColor = UIColor.clear
    titleLabel.textColor = UIColor.schBlack
    titleLabel.font = UIFont.schTextStyle2Font()
    titleLabel.text = titleString;
    titleLabel.sizeToFit()

    let subTitleLabel = UILabel.init(frame: CGRect.init(x: 0, y: 22, width: 0, height: 0))
    subTitleLabel.backgroundColor = UIColor.clear
    subTitleLabel.textColor = UIColor.schBrownishGrey
    subTitleLabel.font = UIFont.schTextStyle3Font()
    subTitleLabel.text = subTitleString;
    subTitleLabel.sizeToFit()

    let twoLineTitleView = UIView.init(frame: CGRect.init(x: 0, y: 0, width: self.view.frame.width-40, height: 30))
    twoLineTitleView.addSubview(titleLabel)
    twoLineTitleView.addSubview(subTitleLabel)

    /*

    float widthDiff = subTitleLabel.frame.size.width - titleLabel.frame.size.width;
    if (widthDiff > 0) {
        CGRect frame = titleLabel.frame;
        frame.origin.x = widthDiff / 2;
        titleLabel.frame = CGRectIntegral(frame);
    }else{
        CGRect frame = subTitleLabel.frame;
        frame.origin.x = abs(widthDiff) / 2;
        subTitleLabel.frame = CGRectIntegral(frame);
    }
    */

    self.navigationItem.titleView = twoLineTitleView;
like image 69
Erwan Avatar answered Nov 14 '22 04:11

Erwan


An alternative approach may be to use a prompt.

like image 11
bobnoble Avatar answered Nov 14 '22 05:11

bobnoble


A few additions to Brian van den hovel's answer to better centralise title and subtitle.

func setTitle(title:String, subtitle:String) -> UIView {
    //Create a label programmatically and give it its property's
    let titleLabel = UILabel(frame: CGRectMake(0, 0, 0, 0)) //x, y, width, height where y is to offset from the view center
    titleLabel.backgroundColor = UIColor.clearColor()
    titleLabel.textColor = UIColor.blackColor()
    titleLabel.font = UIFont.boldSystemFontOfSize(17)
    titleLabel.text = title
    titleLabel.sizeToFit()

    //Create a label for the Subtitle
    let subtitleLabel = UILabel(frame: CGRectMake(0, 18, 0, 0))
    subtitleLabel.backgroundColor = UIColor.clearColor()
    subtitleLabel.textColor = UIColor.lightGrayColor()
    subtitleLabel.font = UIFont.systemFontOfSize(12)
    subtitleLabel.text = subtitle
    subtitleLabel.sizeToFit()

    // Create a view and add titleLabel and subtitleLabel as subviews setting
    let titleView = UIView(frame: CGRectMake(0, 0, max(titleLabel.frame.size.width, subtitleLabel.frame.size.width), 30))

    // Center title or subtitle on screen (depending on which is larger)
    if titleLabel.frame.width >= subtitleLabel.frame.width {
        var adjustment = subtitleLabel.frame
        adjustment.origin.x = titleView.frame.origin.x + (titleView.frame.width/2) - (subtitleLabel.frame.width/2)
        subtitleLabel.frame = adjustment
    } else {
        var adjustment = titleLabel.frame
        adjustment.origin.x = titleView.frame.origin.x + (titleView.frame.width/2) - (titleLabel.frame.width/2)
        titleLabel.frame = adjustment
    }

    titleView.addSubview(titleLabel)
    titleView.addSubview(subtitleLabel)

    return titleView
}
like image 9
Rodrigo Pinto Avatar answered Nov 14 '22 05:11

Rodrigo Pinto