ios - UITableViewCell contentView 具有 autoResizingMask 约束 'UIView-Encapsulated-Layout-Height' 与自动调整大小的自动布局冲突

标签 ios swift uitableview uikit

我正在尝试创建一个表格 View ,其单元格在选择单元格时展开,并保持展开状态,直到再次选择。

我试图让单元格的高度由其内容决定。我已经知道设置 tableView 的 rowHeight 和 estimagedRowHeight 以使 self 调整大小正常工作,所以这不是问题。

ViewController.swift:

import UIKit

class ViewController: UIViewController {

    lazy var tableView: UITableView = {
        let tv = UITableView(frame: .zero, style: .plain)
        tv.register(ExpandingCell.self, forCellReuseIdentifier: ExpandingCell.reuseIdentifier)
        tv.estimatedRowHeight = 85.0
        tv.rowHeight = UITableViewAutomaticDimension
        return tv
    }()


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        self.view.addSubview(tableView)
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: self.view.topAnchor),
            tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
            tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)])


        tableView.dataSource = self
        tableView.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 50
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: ExpandingCell.reuseIdentifier, for: indexPath) as! ExpandingCell
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50.0
    }

}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    }
    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {

    }
}

ExpandingCell.swift

import UIKit

class ExpandingCell: UITableViewCell {
    static let reuseIdentifier = "dafasdfadfagr"

    let minimumDisplayedView = UIView()
    let extraContentView = UIView()
    var expandingConstraint: NSLayoutConstraint?

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }

    private func commonInit() {
        self.setupViews()
        self.contentView.clipsToBounds = true
    }
    private func setupViews() {
        self.addSubviews()
        self.customizeSubviews()
        self.constrainSubviews()
    }

    private func addSubviews() {
        self.contentView.addSubview(minimumDisplayedView)
        self.contentView.addSubview(extraContentView)
    }
    private func customizeSubviews() {
        self.customizeMinimumDisplayedView()
        self.customizeExtraContentView()
    }
    private func constrainSubviews() {
        self.constrainMinimumDisplayedView()
        self.constrainExtraContentView()
    }

    // MARK: - MinimumDisplayView
    private func customizeMinimumDisplayedView() {
        minimumDisplayedView.backgroundColor = .blue
    }
    private func constrainMinimumDisplayedView() {
        minimumDisplayedView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            minimumDisplayedView.heightAnchor.constraint(equalToConstant: 50),
            minimumDisplayedView.topAnchor.constraint(equalTo: self.contentView.topAnchor),
            minimumDisplayedView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
            minimumDisplayedView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor)
            ])
        expandingConstraint = minimumDisplayedView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
        expandingConstraint?.isActive = true
    }

    // MARK: - ExtraContentView
    private func customizeExtraContentView() {
        extraContentView.backgroundColor = .red
    }
    private func constrainExtraContentView() {
        extraContentView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            extraContentView.heightAnchor.constraint(equalToConstant: 200),
            extraContentView.topAnchor.constraint(equalTo: minimumDisplayedView.bottomAnchor),
            extraContentView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
            extraContentView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor)
            ])
    }

    // MARK: - Animate Expansion
//    override func setSelected(_ selected: Bool, animated: Bool) {
//        super.setSelected(selected, animated: animated)
//        print("selected: \(selected)")
//        resize(selected)
//    }

    private func resize(_ expand: Bool) {
        expandingConstraint?.isActive = false
        if expand {
            expandingConstraint = extraContentView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
            expandingConstraint?.isActive = true
        } else {
            expandingConstraint = minimumDisplayedView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
            expandingConstraint?.isActive = true
        }
        UIView.animate(withDuration: 0.3) {
            self.layoutIfNeeded()
        }
    }

}

我有 2 个 View 被添加到 contentView 中,并在初始化单元格时将 contentView 的边缘仅固定到第一个 View 。第一个 View 是蓝色且短的,而第二个 View 是红色且高的。

我希望 tableView 最初看起来全是蓝色,但它看起来像这样: incorrectly shown cells

我怀疑这与 View 生命周期中单元格的布局方式有关,所以我也遇到了这个答案:reload tableview after first load as a workaround

当我运行代码时,我收到这些约束错误

2018-05-05 18:00:15.108634-0400 TestExpandingCells[1022:13932317] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. 
Try this: 
    (1) look at each constraint and try to figure out which you don't expect; 
    (2) find the code that added the unwanted constraint or constraints and fix it. 
(
"<NSLayoutConstraint:0x6000000961c0 UIView:0x7fe583700df0.height == 50   (active)>",
"<NSLayoutConstraint:0x600000096580 V:|-(0)-[UIView:0x7fe583700df0]   (active, names: '|':UITableViewCellContentView:0x7fe583704850 )>",
"<NSLayoutConstraint:0x600000096760 UIView:0x7fe583700df0.bottom == UITableViewCellContentView:0x7fe583704850.bottom   (active)>",
"<NSLayoutConstraint:0x600000096bc0 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fe583704850.height == 50   (active)>"
)

该列表中的最后一个约束“UIView-Encapsulated-Layout-Height”似乎来自 UIKit 为布局单元格创建的一些 autoresizingmask-to-constraint 事物。

所以我的问题是,如何消除这个限制,让 AutoLayout 完全处理我的单元格的制作,而不需要解决方法。 我还希望将其全部包含在 ExpansionCell 类中,而不是将其包含在 tableview 的委托(delegate)方法中。

如果您还找到了使用 AutoLayout 触发单元格扩展的方法,那就加分了。

最佳答案

首先要消除约束冲突,将连接到 contentView 的任何 View 的底部约束的优先级设置为 999 ,其次触发扩展 Hook 高度约束并更改它,还在模型中声明任何 bool 值数组确定单元格是否展开以在滚动后恢复单元格状态

cellForRow

cell.viewHeighcon.constant = isExpanded ? 200 : 50

关于ios - UITableViewCell contentView 具有 autoResizingMask 约束 'UIView-Encapsulated-Layout-Height' 与自动调整大小的自动布局冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50194624/

相关文章:

ios - 数组中的图像未显示在 UICollectionview 中

ios - 快速避免索引超出范围错误

swift - iOS AVMutableComposition 添加文字叠加

swift - UIButton 在 Swift 3 中更新 UITableView

ios - fetchedResultsController.fetchedObjects.count = 0 但它充满了对象

ios - 自定义注释苹果mapkit

ios - StartMonitoringSignificantLocationChanges 方法不返回位置

Swift prepareForSegue 初始化空数组

iphone - UITableView:删除带有动画的部分

ios - 如何从 json 字典自动创建模型类(NSObject)?