使用UIStackView动态UITableView行高?

时间:2016-03-26 17:46:09

标签: ios xcode uitableview autolayout uistackview

感到惊讶的是,这不是开箱即用的,因为这似乎是堆栈视图的一个重要用例。我有一个UITableViewCell子类,它将一个UIStackView添加到contentView。我在tableView(_cellForRowAtIndexPath:)中向堆栈视图添加标签,并且tableview设置为使用动态行高,但它似乎不起作用,至少在Xcode 7.3中。我还认为隐藏在堆栈视图中的已安排的子视图是可动画的,但这似乎也被打破了。

有关如何使其正常工作的任何想法?

w3c HTML5 Specs tbody

class StackCell : UITableViewCell {
    enum VisualFormat: String {
        case HorizontalStackViewFormat = "H:|[stackView]|"
        case VerticalStackViewFormat = "V:|[stackView(>=44)]|"
    }

    var hasSetupConstraints = false
    lazy var stackView : UIStackView! = {
        let stack = UIStackView()
        stack.axis = .Vertical
        stack.distribution = .FillProportionally
        stack.alignment = .Fill
        stack.spacing = 3.0
        stack.translatesAutoresizingMaskIntoConstraints = false
        return stack
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        contentView.addSubview(stackView)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func updateConstraints() {
        if !hasSetupConstraints {
            hasSetupConstraints = true
            let viewsDictionary: [String:AnyObject] = ["stackView" : stackView]
            var newConstraints = [NSLayoutConstraint]()
            newConstraints += self.newConstraints(VisualFormat.HorizontalStackViewFormat.rawValue, viewsDictionary: viewsDictionary)
            newConstraints += self.newConstraints(VisualFormat.VerticalStackViewFormat.rawValue, viewsDictionary: viewsDictionary)
            addConstraints(newConstraints)
        }
        super.updateConstraints()
    }

    private func newConstraints(visualFormat: String, viewsDictionary: [String:AnyObject]) -> [NSLayoutConstraint] {
        return NSLayoutConstraint.constraintsWithVisualFormat(visualFormat, options: [], metrics: nil, views: viewsDictionary)
    }

class ViewController: UITableViewController {

    private let reuseIdentifier = "StackCell"
    private let cellClass = StackCell.self

    override func viewDidLoad() {
        super.viewDidLoad()
        configureTableView(self.tableView)
    }

    private func configureTableView(tableView: UITableView) {
        tableView.registerClass(cellClass, forCellReuseIdentifier: reuseIdentifier)
        tableView.separatorStyle = .SingleLine
        tableView.estimatedRowHeight = 88
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    private func newLabel(title: String) -> UILabel {
        let label = UILabel()
        label.text = title
        return label
    }

    // MARK: - UITableView
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 4
    }

    override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 44.0
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier, forIndexPath: indexPath) as! StackCell
        cell.stackView.arrangedSubviews.forEach({$0.removeFromSuperview()})
        cell.stackView.addArrangedSubview(newLabel("\(indexPath.section)-\(indexPath.row)"))
        cell.stackView.addArrangedSubview(newLabel("Second Label"))
        cell.stackView.addArrangedSubview(newLabel("Third Label"))
        cell.stackView.addArrangedSubview(newLabel("Fourth Label"))
        cell.stackView.addArrangedSubview(newLabel("Fifth Label"))
        return cell
    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let cell = tableView.cellForRowAtIndexPath(indexPath) as! StackCell
        for (idx, view) in cell.stackView.arrangedSubviews.enumerate() {
            if idx == 0 {
                continue
            }
            view.hidden = !view.hidden
        }
        UIView.animateWithDuration(0.3, animations: {
            cell.contentView.layoutIfNeeded()
            tableView.beginUpdates()
            tableView.endUpdates()

        })
    }
}

1 个答案:

答案 0 :(得分:22)

为了实现这一点,似乎需要在UITableViewCell的init中添加约束,并将其添加到contentView而不是单元格的视图中。

enter image description here

工作代码如下所示:

import UIKit
class StackCell : UITableViewCell {
    enum VisualFormat: String {
        case HorizontalStackViewFormat = "H:|[stackView]|"
        case VerticalStackViewFormat = "V:|[stackView(>=44)]|"
    }

    var hasSetupConstraints = false
    lazy var stackView : UIStackView! = {
        let stack = UIStackView()
        stack.axis = UILayoutConstraintAxis.Vertical
        stack.distribution = .FillProportionally
        stack.alignment = .Fill
        stack.spacing = 3.0
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.setContentCompressionResistancePriority(UILayoutPriorityRequired, forAxis: .Vertical)
        return stack
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        contentView.addSubview(stackView)
        addStackConstraints()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func addStackConstraints() {
        let viewsDictionary: [String:AnyObject] = ["stackView" : stackView]
        var newConstraints = [NSLayoutConstraint]()
        newConstraints += self.newConstraints(VisualFormat.HorizontalStackViewFormat.rawValue, viewsDictionary: viewsDictionary)
        newConstraints += self.newConstraints(VisualFormat.VerticalStackViewFormat.rawValue, viewsDictionary: viewsDictionary)
        contentView.addConstraints(newConstraints)
        super.updateConstraints()
    }

    private func newConstraints(visualFormat: String, viewsDictionary: [String:AnyObject]) -> [NSLayoutConstraint] {
        return NSLayoutConstraint.constraintsWithVisualFormat(visualFormat, options: [], metrics: nil, views: viewsDictionary)
    }
}