UINavigationBar TitleView with subtitle

后端 未结 9 748
一生所求
一生所求 2021-01-01 21:09

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

相关标签:
9条回答
  • 2021-01-01 21:27

    You can also use an attributed string to achieve the same result:

    let subtitleAttribute = [NSForegroundColorAttributeName: UIColor.grayColor() , NSFontAttributeName: UIFont.systemFontOfSize(12.0)]
    let titleString = NSMutableAttributedString(string: "title" + "\n", attributes: [NSFontAttributeName: UIFont.boldSystemFontOfSize(17.0)])
    let subtitleString = NSAttributedString(string: "subtitle", attributes: subtitleAttribute)
    titleString.appendAttributedString(subtitleString)
    
    let label = UILabel(frame: CGRectMake(0, 0, titleString.size().width, 44))
    label.numberOfLines = 0
    label.textAlignment = NSTextAlignment.Center
    label.attributedText = titleString
    self.navigationItem.titleView = label
    

    Swift 3

    let subtitleAttribute = [NSForegroundColorAttributeName: UIColor.gray , NSFontAttributeName: UIFont.systemFont(ofSize: 12.0)]
    let titleString = NSMutableAttributedString(string: "title" + "\n", attributes: [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 17.0)])
    let subtitleString = NSAttributedString(string: "subtitle", attributes: subtitleAttribute)
    titleString.append(subtitleString)
    
    let label = UILabel(frame: CGRect(x: 0, y: 0, width: titleString.size().width, height: 44))
    label.numberOfLines = 0
    label.textAlignment = NSTextAlignment.center
    label.attributedText = titleString
    self.navigationItem.titleView = label
    
    0 讨论(0)
  • 2021-01-01 21:38

    https://www.reddit.com/r/swift/comments/3izq7b/style_guidelines_for_navigation_bar_prompts/

    extension UINavigationItem {
    
        //Make the title 2 lines with a title and a subtitle
        func addTitleAndSubtitleToNavigationBar (title: String, subtitle: String) {
            var label = UILabel(frame: CGRectMake(10.0, 0.0, 50.0, 40.0))
            label.font = UIFont.boldSystemFontOfSize(14.0)
            label.numberOfLines = 2
            label.text = "\(title)\n\(subtitle)"
            label.textColor = UIColor.blackColor()
            label.sizeToFit()
            label.textAlignment = NSTextAlignment.Center
            self.titleView = label
        }
    }
    
    0 讨论(0)
  • 2021-01-01 21:40

    I did this by completely replacing the title view. The end result looks like this:

    It can be achieved with the following code in the viewDidLoad method.

    UIView * containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 220, 40)];
    
    UILabel * titleLabel = [[UILabel alloc] init];
    titleLabel.text = @"Ttitle";
    titleLabel.textAlignment = NSTextAlignmentCenter;
    titleLabel.font = [UIFont boldSystemFontOfSize:titleLabel.font.pointSize];
    
    [containerView addSubview:titleLabel];
    titleLabel.keepInsets.equal = 0;
    titleLabel.keepBottomInset.equal = 10;
    
    UILabel * subtitleLabel = [[UILabel alloc] init];
    subtitleLabel.textAlignment = NSTextAlignmentCenter;
    subtitleLabel.font = [UIFont italicSystemFontOfSize:12.0];
    subtitleLabel.textColor = [UIColor lightGrayColor];
    
    [containerView addSubview:subtitleLabel];
    
    subtitleLabel.keepHeight.equal = 15;
    subtitleLabel.keepWidth.equal = 200;
    subtitleLabel.keepBottomInset.equal = 0;
    subtitleLabel.keepHorizontalCenter.equal = 0.5;
    
    subtitleLabel.text = @"Subtitle";
    
    [self.navigationItem setTitleView:containerView];
    

    To do this I used the excellent KeepLayout library. It yields a result like this:

    0 讨论(0)
  • 2021-01-01 21:40

    Inspired by @Ben Smiley, I added a masonry implementation.

    CGFloat width = 200;
    CGFloat titleHeight = 25;
    CGFloat containerHeight = 40;
    
    UIView * containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, containerHeight)];
    UILabel * titleLabel = [[UILabel alloc] init];
    titleLabel.text = @"Title";
    titleLabel.textAlignment = NSTextAlignmentCenter;
    titleLabel.font = [UIFont boldSystemFontOfSize:titleLabel.font.pointSize];
    
    [containerView addSubview:titleLabel];
    [titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(0);
        make.left.mas_equalTo(0);
        make.right.mas_equalTo(0);
        make.width.mas_equalTo(width);
        make.height.mas_equalTo(titleHeight);
    
    }];
    
    UILabel * subtitleLabel = [[UILabel alloc] init];
    subtitleLabel.textAlignment = NSTextAlignmentCenter;
    subtitleLabel.font = [UIFont systemFontOfSize:12];
    
    [containerView addSubview:subtitleLabel];
    
    [subtitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(0);
        make.right.mas_equalTo(0);
        make.top.mas_equalTo(titleLabel.mas_bottom);
        make.width.mas_equalTo(width);
        make.height.mas_equalTo(containerHeight - titleHeight);
    
    }];
    
    subtitleLabel.text = @"Subtitle";
    
    [self.navigationItem setTitleView:containerView];
    
    0 讨论(0)
  • In addition to the github! here.

    I found that when my subtitle was smaller than my Title it would not format it correctly here is the right code.

    //Usage:
    self.navigationItem.titleView = setTitle(varDec.currentDate(), subtitle: varDec.currentDay())
    
     func setTitle(title:String, subtitle:String) -> UIView {
        //Create a label programmatically and give it its property's
        let titleLabel = UILabel(frame: CGRectMake(0, -5, 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
        // x, y, width, height where x is set to be half the size of the title (100/4 = 25%) as it starts all the way left.
        let subtitleLabel = UILabel(frame: CGRectMake(titleLabel.frame.size.width / 4, 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 
         * its width to the bigger of both
         * this will crash the program if subtitle is bigger then title
         */
        let titleView = UIView(frame: CGRectMake(0, 0, max(titleLabel.frame.size.width, subtitleLabel.frame.size.width), 30))
        titleView.addSubview(titleLabel)
        titleView.addSubview(subtitleLabel)
    
    
        return titleView
    }
    
    0 讨论(0)
  • 2021-01-01 21:46

    I was using Rodrigo Pedroso's answer, but the fact that it doesn't truncate long titles became a problem. I made a version that measures how much space there is for the title between the bar button items, and then manually truncates the title to fit in that space. The truncation code was adapted from this answer, and is a bit of a mess - maybe someone can help figure out a way to use UILabel's built-in truncation methods (i.e. .ByTruncatingTail). I've already spent too much time on this though.

    Here's what I've got:

    extension UIViewController {
    
        private var availableWidthForTitle: CGFloat {
            get {
                var total = UIScreen.mainScreen().bounds.width
                if let navigationBar = navigationController?.navigationBar {
                    var maxYLeft:  CGFloat = 0
                    var minYRight: CGFloat = 0
                    for subview in navigationBar.subviews.dropFirst()
                        where !subview.hidden {
                        if subview.frame.origin.x < total / 2 {
                            let rightEdge = subview.frame.origin.x + subview.frame.size.width
                            if rightEdge < total / 2 {
                                maxYLeft = max(maxYLeft, rightEdge)
                            }
                        } else {
                            let leftEdge = subview.frame.origin.x
                            if leftEdge > total / 2 {
                                minYRight = min(minYRight, total - leftEdge)
                            }
                        }
                    }
                    total = total - maxYLeft - minYRight
                }
    
                return total
            }
        }
    
        func setTitle(title:String, subtitle:String?) {
            if (subtitle == nil) {
                self.title = title.uppercaseString
            } else {
                let titleLabel = UILabel(frame: CGRectMake(0, -2, 0, 0))
                titleLabel.backgroundColor = UIColor.clearColor()
                titleLabel.textColor = MaterialColor.white
                titleLabel.font = RobotoFont.boldWithSize(17)
                titleLabel.textAlignment = .Center
                let availableWidth = availableWidthForTitle
                let titleUppercase = NSString(string: title.uppercaseString)
                if titleUppercase.boundingRectWithSize(
                    // if title needs to be truncated
                    CGSize(width: CGFloat.max, height: CGFloat.max),
                    options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                    attributes: [NSFontAttributeName : titleLabel.font],
                    context: nil).width > availableWidth {
                    let truncTitle: NSMutableString = ""
                    for nextChar in title.uppercaseString.characters {
                        if truncTitle.boundingRectWithSize(
                            CGSize(width: CGFloat.max, height: CGFloat.max),
                            options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                            attributes: [NSFontAttributeName : titleLabel.font],
                            context: nil).width > availableWidth - 16 { // for ellipsis + some margin
                            truncTitle.appendString("...")
                            break
                        } else {
                            truncTitle.appendString(String(nextChar))
                        }
                    }
                    titleLabel.text = truncTitle as String
                } else {
                    // use title as-is
                    titleLabel.text = titleUppercase as String
                }
                titleLabel.sizeToFit()
                let subtitleLabel = UILabel(frame: CGRectMake(0, 18, 0, 0))
                subtitleLabel.backgroundColor = UIColor.clearColor()
                subtitleLabel.textColor = MaterialColor.white
                subtitleLabel.font = MaterialFont.italicSystemFontWithSize(10)
                subtitleLabel.text = subtitle
                subtitleLabel.sizeToFit()
    
                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)
                self.navigationItem.titleView = titleView
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题