Ios 如何创建高度由标签高度决定的UITableView标题?

Ios 如何创建高度由标签高度决定的UITableView标题?,ios,swift,Ios,Swift,我想在我的tableView中添加一个标题。此标题包含1个UILabel。收割台高度应根据标签的行数计算 在我的代码中,我使用标签标题的所有边添加约束。这是我的尝试: //Add header to tableView header = UIView() header.backgroundColor = UIColor.yellowColor() tableView!.tableHeaderView = header //Create Label and

我想在我的tableView中添加一个标题。此标题包含1个UILabel。收割台高度应根据标签的行数计算

在我的代码中,我使用标签标题的所有边添加约束。这是我的尝试:

    //Add header to tableView
    header = UIView()
    header.backgroundColor = UIColor.yellowColor()
    tableView!.tableHeaderView = header

    //Create Label and add it to the header
    postBody = UILabel()
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog."
    postBody.font = UIFont(name: "Lato-Regular", size: 16.0)
    postBody.numberOfLines = 0
    postBody.backgroundColor = FlatLime()
    header.addSubview(postBody)

    //Enable constraints for each item
    postBody.translatesAutoresizingMaskIntoConstraints = false
    header.translatesAutoresizingMaskIntoConstraints = false

    //Add constraints to the header and post body
    let postBodyLeadingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
    postBodyLeadingConstraint.active = true

    let postBodyTrailingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
    postBodyTrailingConstraint.active = true


    let postBodyTopConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    postBodyTopConstraint.active = true


    let postBodyBottomConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)
    postBodyBottomConstraint.active = true


    //Calculate header size
    let size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
    var frame = header.frame
    frame.size.height = size.height
    header.frame = frame
    tableView!.tableHeaderView = header
    header.layoutIfNeeded()
这是我的桌子:

    let nib = UINib(nibName: "MessagesTableViewCell", bundle: nil)
    let nibSimple = UINib(nibName: "SimpleMessagesTableViewCell", bundle: nil)
    self.tableView!.registerNib(nib, forCellReuseIdentifier: "MessagesTableViewCell")
    self.tableView!.registerNib(nibSimple, forCellReuseIdentifier: "SimpleMessagesTableViewCell")
    self.tableView!.dataSource = self
    self.tableView!.delegate = self
    self.tableView!.rowHeight = UITableViewAutomaticDimension
    self.tableView!.estimatedRowHeight = 100.0
    self.tableView!.separatorStyle = UITableViewCellSeparatorStyle.None
    self.tableView!.separatorColor = UIColor(hex: 0xf5f5f5)
    self.tableView!.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
    self.tableView!.clipsToBounds = true
    self.tableView!.allowsSelection = false
    self.tableView!.allowsMultipleSelection = false
    self.tableView!.keyboardDismissMode = .OnDrag
正如您所看到的,标题没有考虑标签的高度(我做的是numberOfLines=0)


您可以使用标签的字符串计算标签的高度

let labelWidth = label.frame.width
let maxLabelSize = CGSize(width: labelWidth, height: CGFloat.max)
let actualLabelSize = label.text!.boundingRectWithSize(maxLabelSize, options: [.UsesLineFragmentOrigin], attributes: [NSFontAttributeName: label.font], context: nil)
let labelHeight = actualLabelSize.height

UILabel
s利用
UIView
intrinsicContentSize()
告诉自动布局它们应该是什么大小。但是,对于多行标签,固有内容大小是不明确的;这张桌子不知道它是短是宽,是高是窄,还是介于两者之间

为了解决这个问题,
UILabel
有一个名为
preferredMaxLayoutWidth
的属性。设置此选项告诉多行标签,它最多应该有这么宽,并允许
intrinsicContentSize()
计算并返回一个适当的高度以匹配。在您的示例中,通过不设置
preferredMaxLayoutWidth
,标签将其宽度保持为无限,从而计算长单行文本的高度

preferredMaxLayoutWidth
的唯一复杂之处是,在自动布局为您计算出一个宽度之前,您通常不知道希望标签的宽度。因此,在视图控制器子类(它看起来像您的代码示例可能来自)中设置它的位置在
viewdilayoutsubviews

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    postBody.preferredMaxLayoutWidth = CGRectGetWidth(postBody.frame)
    // then update the table header view
    if let header = tableView?.tableHeaderView {
        header.frame.size.height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        tableView?.tableHeaderView = header
    }
}
显然,您需要为
postBody
标签添加一个属性,这样才能工作


如果您不在
UIViewController
子类中,请告诉我,我将编辑我的答案。

我们遇到的第一个问题是无法通过自动布局调整标题大小,有关详细信息,请参阅

因此,我们必须手动计算收割台的高度,例如:

@IBOutlet var table: UITableView!

var header: UIView?
var postBody: UILabel?

override func viewDidLoad() {
    super.viewDidLoad()

    let header = UIView()
    // don't forget to set this
    header.translatesAutoresizingMaskIntoConstraints = true
    header.backgroundColor = UIColor.yellowColor()

    let postBody = UILabel()
    postBody.translatesAutoresizingMaskIntoConstraints = false
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog."
    postBody.font = UIFont.systemFontOfSize(16.0)

    // don't forget to set this
    postBody.lineBreakMode = .ByWordWrapping
    postBody.numberOfLines = 0

    header.addSubview(postBody)

    let leadingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0)
    let trailingConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Trailing, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Trailing, multiplier: 1, constant: 0)
    let topConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)
    let bottomConstraint = NSLayoutConstraint(item: postBody, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: header, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0)

    header.addConstraints([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint])

    self.table.tableHeaderView = header

    self.header = header
    self.postBody = postBody
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    let text = postBody!.attributedText!

    let height = text.boundingRectWithSize(
        CGSizeMake(table.bounds.size.width, CGFloat.max),
        options: [.UsesLineFragmentOrigin],
        context: nil
    ).height

    header!.frame.size.height = height
}
您可能还希望在中使用代码。如何计算高度并不重要。关键是自动布局不会自动用于
tableHeaderView

结果:

使用故事板的实现

  • UItableView
    中添加
    UITableViewCell
    new
    UIView
    并将其放入
    UILabel
    通过自动布局将它们连接起来
  • UILabel
    中,将行数设置为0
  • ViewDidLoad
    中,您的
    UILabel
    调用一个方法
    sizeToFit()
    并为
    UIView
    指定一个大小,这将是您的headerView
    headerView.frame.size.height=headerLabel.frame.size.height
  • 代码

    截图

    测试项目


    我们使用NSLayoutManager快速估计需要根据文本调整大小的项目的高度。这是基本思想:

    override class func estimatedHeightForItem(text: String, atWidth width: CGFloat) -> CGFloat {
    
        let storage = NSTextStorage(string: text!)
        let container = NSTextContainer(size: CGSize(width: width, height: CGFloat.max))
        let layoutManager = NSLayoutManager()
        layoutManager.addTextContainer(container)
        storage.addLayoutManager(layoutManager)
        storage.addAttribute(NSFontAttributeName, value: UIFont.Body, range: NSRange(location: 0, length: storage.length))
        container.lineFragmentPadding = 0.0
    
        return layoutManager.usedRectForTextContainer(container).size.height 
    }
    

    可能更适合您的用例,但我发现更好地控制布局的处理方式很好。

    //可能会对您有所帮助

    header = UIView(frame: CGRectMake(tableview.frame.origin.x,tableview.frame.origin.y, tableview.frame.size.width, 40))
    header.backgroundColor = UIColor.yellowColor()
    
    //Create Label and add it to the header
    postBody = UILabel(frame: header.frame)
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog."
    postBody.font = UIFont(name: "Lato-Regular", size: 16.0)
    postBody.numberOfLines = 0
    postBody.backgroundColor = FlatLime()
    header.addSubview(postBody)
    
    let maximumLabelSize: CGSize = CGSizeMake(postBody.size.width, CGFloat.max);
    
    let options: NSStringDrawingOptions  = NSStringDrawingOptions.UsesLineFragmentOrigin
    let context: NSStringDrawingContext = NSStringDrawingContext()
            context.minimumScaleFactor = 0.8
            let attr: Dictionary = [NSFontAttributeName: postBody.font!]
            var size: CGSize? = postBody.text?.boundingRectWithSize(maximumLabelSize, options:options, attributes: attr, context: context).size
    
    let frame = header.frame
    frame.size.height = size?.height
    header.frame = frame
    postBody.frame = frame
    tableView!.tableHeaderView = header
    

    是否可以发布表视图主要方法代码?如果设置断点,将帧分配回页眉时帧的外观如何?是否缺少postBody.TranslatesAutoResizezingMaskinToConstraints=false?它是否需要是页眉,或者是否可以将页眉视图约束在表视图顶部?另外,看起来您并没有将标签调整到某个宽度。这可能会增加它的高度。不确定您是否在代码中的其他地方有它?嗯,这是针对节标题,而不是针对表标题。完全不同的事情。
    header = UIView(frame: CGRectMake(tableview.frame.origin.x,tableview.frame.origin.y, tableview.frame.size.width, 40))
    header.backgroundColor = UIColor.yellowColor()
    
    //Create Label and add it to the header
    postBody = UILabel(frame: header.frame)
    postBody.text = "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog."
    postBody.font = UIFont(name: "Lato-Regular", size: 16.0)
    postBody.numberOfLines = 0
    postBody.backgroundColor = FlatLime()
    header.addSubview(postBody)
    
    let maximumLabelSize: CGSize = CGSizeMake(postBody.size.width, CGFloat.max);
    
    let options: NSStringDrawingOptions  = NSStringDrawingOptions.UsesLineFragmentOrigin
    let context: NSStringDrawingContext = NSStringDrawingContext()
            context.minimumScaleFactor = 0.8
            let attr: Dictionary = [NSFontAttributeName: postBody.font!]
            var size: CGSize? = postBody.text?.boundingRectWithSize(maximumLabelSize, options:options, attributes: attr, context: context).size
    
    let frame = header.frame
    frame.size.height = size?.height
    header.frame = frame
    postBody.frame = frame
    tableView!.tableHeaderView = header