UITableView的tableHeaderView高度的自适应

  前段时间碰到一个要求对UITableHeaderView的高度随内容高度自适应的需求。讲到根据内容自适应,在Autolayout到来后越来越容易了。

Apple对自适应的支持

  之所以UIlabel,UIButton, UIImageView能根据内容自适应,是因为有一个IntrinsicContentSize。有了它就可以自己根据内容调整大小,再也不用量宽和高了。对IntrinsicContentSize的支持Apple也给了一个表:

View Intrinsic Content Size
View And NSView No intrinsic content size.
Sliders Defines Only The Width.
Labels,buttons,switches,and text fields Define both the height and the width.
Text views and Image views intrinsic content size can vary.
* UIView和NSView是没有IntrinsicContentSize的。
* Sliders只有with有这个属性。 Sliders只能定义width。Sliders的height拥有IntrinsicContentSize(感谢@凸小布,发现了这个问题)
* Labels, buttons, switches, text fields比较棒,属性完美支持
* Text views和image views也挺好,在有内容的时候支持,没有内容的时候不支持。

  虽然UIView没有IntrinsicContentSize,但如果我们自定义一个View,又想要他拥有默认宽高,只需要重写IntrinsicContentSize方法,便可让其拥有默认的宽高。在storyboard/xib中的Size Inspector也有争对这一块的设置。(比如UIImage放在UIScrollView中,当没有给UIImage设置图片时,storyboard会有约束警告,在Size Inspector中设置placeHolder的宽高即可)。 Intrinsic size

tableHeaderView高度自适应

这里自定义的tableHeader的结构如下图 UITableHeaderView

  因为iOS并没有提供像给UITableViewCell设置自适应高度的方法

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
}

  所以tableHeaderView的高度还是要根据内容来计算,只是这个计算过程可以充分利用其子视图的intrinsic特点来自动给我们算出来,这里通过给UITableView扩展一个方法来做,如下

extension UITableView {

    func setAndLayoutTableHeaderView(header: UIView) {
        self.tableHeaderView = header
        //Tip:这里要先计算子视图的高度后,再去更新tableHeaderView的布局
        for view in header.subviews {
            guard let label = view as? UILabel where label.numberOfLines == 0 else { continue }
            //设置子视图的preferredMaxLayoutWidth
            label.preferredMaxLayoutWidth = CGRectGetWidth(label.frame)
        }
        //更新tableHeaderView的布局
        header.setNeedsLayout()
        header.layoutIfNeeded()
        var frame = header.frame

//        let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
//        //let height = header.systemLayoutSizeFittingSize(UILayoutFittingExpandedSize).height
//        frame.size.height = height

        let size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
        frame.size = size

        header.frame = frame
        self.tableHeaderView = header
    }

}

  最后调用再这样简单调用一下:

    override func viewDidLoad() {
        super.viewDidLoad()
        //tableHeaderView指定为storyboard中自定义的headerView
        self.tableView.tableHeaderView = headerView
        //设置tableHeaderView高度自
        self.tableView.setAndLayoutTableHeaderView(headerView)

        self.tableView.tableFooterView = footerView
        //self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
        //self.tableView.estimatedSectionHeaderHeight = 1;
    }
{{ message }}

{{ 'Comments are closed.' | trans }}