【问题标题】:UINavigationBar TitleView with subtitleUINavigationBar TitleView 带字幕
【发布时间】:2012-10-16 11:46:09
【问题描述】:

我想在 UINavigationBar 中添加一个 titleView,它有两行文本,而不是只有一行

当我有一个“后退”按钮和一个“编辑”按钮时,我当前的实现效果很好,因为它看起来几乎居中。问题是当我只有一个按钮时。它看起来非常奇怪和错误,因为视图以可用空间为中心。

UINavigationBar with left and right Button

UINavigationBar with only one Button

这是我当前的实现:

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;

【问题讨论】:

标签: ios uinavigationbar titleview


【解决方案1】:

我会这样做:

  • 对两个标签分别使用 sizeToFit。
  • 将容器视图的宽度设置为两个标签的最大宽度。
  • 将视图中两个标签中较小的一个居中。

这段代码应该适合你:

    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 变体:

    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;

【讨论】:

  • 这两个标签可以使用自动布局吗?
  • @Mbt925 (用于谷歌搜索的人)您可以使用标签,虽然堆栈视图可能是包装器的最佳选择,但您可以将对齐和分布设置为 .fill 并设置高度约束标签。 stackView 将由导航栏调整大小。
【解决方案2】:

另一种方法可能是使用prompt

【讨论】:

  • 是的。对于许多基本用例,使用提示字符串是一个很好的解决方案。完全免费,而且可以正常工作。
  • @lostintranslation 我假设您的意思是在导航标题上方...是的,这就是提示的作用。如果您正在寻找其他东西,那么提示不是适合您的解决方案。
  • @bobnoble 正确并同意。 ser 要求提供字幕,这不是 apple 在使用 prompt 时的意图
【解决方案3】:

对 Brian van den hovel 的回答进行了一些补充,以更好地集中标题和副标题。

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
}

【讨论】:

  • 我发现这个解决方案效果最好。当titleLabel 超过一定数量的字符时,此处的其他解决方案将失败,并且由于某种原因会超过subtitleLabel。这个解决方案虽然不是完美的(长时间的titleLabels 会跑出屏幕)是我迄今为止见过的最好的。
  • 当我在闭包中调用这个函数时,它会在最左边显示标题和副标题,然后它会在一秒钟内将它们移动到中心,这看起来很糟糕,如何解决?
  • 我想要一个解决 cmets 中提到的两个问题的解决方案
  • 非常适合我!!谢谢!
【解决方案4】:

您也可以使用属性字符串来实现相同的结果:

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

斯威夫特 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

【讨论】:

    【解决方案5】:

    除了github!在这里。

    我发现当我的字幕小于我的 Title 时,它​​的格式会不正确,这是正确的代码。

    //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
    }
    

    【讨论】:

      【解决方案6】:

      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
          }
      }
      

      【讨论】:

        【解决方案7】:

        我通过完全替换标题视图来做到这一点。最终结果如下所示:

        可以通过viewDidLoad方法中的如下代码来实现。

        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];
        

        为此,我使用了出色的 KeepLayout 库。它产生这样的结果:

        【讨论】:

          【解决方案8】:

          我使用的是 Rodrigo Pedroso 的 answer,但它不会截断长标题这一事实成为一个问题。我制作了一个版本来测量条形按钮项之间的标题有多少空间,然后手动截断标题以适应该空间。截断代码改编自this answer,有点乱——也许有人可以帮助找出一种使用 UILabel 内置截断方法(即 .ByTruncatingTail)的方法。不过我已经花太多时间在这上面了。

          这是我得到的:

          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
                  }
              }
          }
          

          【讨论】:

            【解决方案9】:

            受@Ben Smiley 的启发,我添加了一个砌体实现。

            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];
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-01-19
              • 2017-03-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-14
              相关资源
              最近更新 更多