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

时间:2016-04-26 06:49:13

标签: ios swift

我想在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)

Header does not auto-height

6 个答案:

答案 0 :(得分:13)

UILabel利用UIView的{​​{1}}告诉自动布局应该是什么尺寸。但是,对于多行标签,内在内容大小不明确;桌子不知道它是否应该短而宽,高而窄,或介于两者之间。

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

preferredMaxLayoutWidth的唯一复杂因素是您通常不知道标签的宽度,直到自动布局为您计算了一个宽度。出于这个原因,在视图控制器子类中设置它的地方(它看起来像你的代码示例可能来自)preferredMaxLayoutWidth

viewDidLayoutSubviews

显然,您需要为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子类中,请告诉我,我会编辑我的答案。

答案 1 :(得分:10)

  

使用故事板实施

  1. UItableView添加UITableViewCell个新UIView并添加UILabel 通过Autolayout连接它们
  2. UILabel中,将行数设为0。
  3. ViewDidLoad您的UILabel调用方法sizeToFit() 并指定UIView的大小,这将是您的HeaderVew headerView.frame.size.height = headerLabel.frame.size.height
  4.   

    代码

        @IBOutlet weak var tableView: UITableView!
        @IBOutlet weak var headerView: UIView!
        @IBOutlet weak var headerLabel: UILabel!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            headerLabel.text = "tableViewdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarningdidReceiveMemoryWarning"
            headerLabel.sizeToFit()
            headerView.frame.size.height = headerLabel.frame.size.height
        }
    
      

    截图

    enter image description here

      

    TestProject

    test project link

答案 2 :(得分:9)

我们遇到的第一个问题是自动布局无法调整标题大小,有关详细信息,请参阅Is it possible to use AutoLayout with UITableView's tableHeaderView?

因此,我们必须手动计算标题的高度,例如:

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

您可能还想使用stefandouganhyde's answer中的代码。你如何计算高度并不重要。关键是自动布局不会自动对tableHeaderView起作用。

结果:

resulting table

答案 3 :(得分:2)

我们使用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 
}

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

答案 4 :(得分:-1)

//可能会对你有帮助。

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

答案 5 :(得分:-2)

您可以使用字符串

计算标签的高度
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