【问题标题】:UITableView when changing constraint which effects height of cell after dequeueing, end up with broken constraintsUITableView 在更改出队后影响单元格高度的约束时,最终会出现损坏的约束
【发布时间】:2016-04-29 03:49:36
【问题描述】:

此代码块试图触及问题的核心。如果在使单元格出列后(通过configure),约束发生了变化,单元格的高度也发生了变化,那么您最终会收到一个损坏的约束警告(Unable to simultaneously satisfy constraints...)。但是,它显示正确。

import UIKit
class ViewController: UIViewController {

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.registerClass(Cell.self, forCellReuseIdentifier: "cell")
        tableView.estimatedRowHeight = 55.0
        tableView.rowHeight = UITableViewAutomaticDimension
    }

}

extension ViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return array.count
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! Cell
        cell.configure(array[indexPath.row])
        return cell
    }

    func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    }
}

enum Position {
    case Top
    case Middle
    case Bottom
}

class Cell: UITableViewCell {

    private var topConstraint: NSLayoutConstraint!
    private var bottomConstraint: NSLayoutConstraint!

    private let label = UILabel()
    private var previous: Position?

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        label.backgroundColor = UIColor.redColor().colorWithAlphaComponent(0.5)
        label.textColor = UIColor.blackColor()
        label.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(label)
        label.leadingAnchor.constraintEqualToAnchor(contentView.leadingAnchor, constant: 30).active = true
        label.trailingAnchor.constraintEqualToAnchor(contentView.trailingAnchor, constant: -30).active = true
        topConstraint = label.topAnchor.constraintEqualToAnchor(contentView.topAnchor)
        topConstraint.active = true
        bottomConstraint = label.bottomAnchor.constraintEqualToAnchor(contentView.bottomAnchor)
        bottomConstraint.active = true
    }

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

    func configure(position: Position) {
        if previous != nil {print("previous \(previous!) new \(position)")}
        topConstraint.constant = position == .Top ? 30 : 0
        bottomConstraint.constant = position == .Bottom ? -30 : 0
        label.text = String(position)
        previous = position
    }
}

let array: [Position] = [.Top, .Middle, .Middle, .Middle, .Bottom,
                         .Top, .Middle, .Middle, .Middle, .Middle, .Bottom,
                         .Top, .Middle, .Middle, .Bottom,
                         .Top, .Middle, .Middle, .Middle,  .Middle, .Middle, .Middle, .Bottom,
                         .Top, .Middle, .Middle, .Middle, .Bottom,
                         .Top, .Bottom,
                         .Top, .Middle, .Middle, .Middle,  .Middle, .Middle, .Middle, .Bottom,
                         .Top, .Middle, .Middle, .Middle, .Bottom,
                         .Top, .Middle, .Middle, .Bottom,
                         .Top, .Middle, .Middle, .Middle,  .Middle, .Middle, .Middle, .Bottom,
]

错误信息是……

2016-04-28 22:56:29.831 test-constraint-change[51059:3776208] 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:0x7c117c70 V:|-(30)-[UILabel:0x7c148770'Middle']   (Names: '|':UITableViewCellContentView:0x7c149b70 )>",
"<NSLayoutConstraint:0x7c115bd0 UILabel:0x7c148770'Middle'.bottom == UITableViewCellContentView:0x7c149b70.bottom>",
"<NSLayoutConstraint:0x7c14a3f0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7c149b70(20.5)]>"
)

Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7c115bd0 UILabel:0x7c148770'Middle'.bottom == UITableViewCellContentView:0x7c149b70.bottom>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

【问题讨论】:

  • 您遇到的错误是什么?请向我们显示确切的堆栈跟踪和错误消息。
  • 完成了,但是这 3 个约束在技术上没有任何问题。当时,他们应该强制单元格高度更大(单元格高度是动态的)。细胞正在从“中间”类型向“顶部”类型生长。

标签: ios swift uitableview constraints


【解决方案1】:

将约束的优先级设置为 999。就像现在一样,它会正确显示。

【讨论】:

  • 感谢您的回复...我相信这可以解决问题。但感觉有点hacky。想找到一种干净的方法来做到这一点。 (我也可以忽略警告)
  • 这是您最干净的解决方案,并且与自动布局的工作方式有关。使用自动调整表格单元格大小,系统会隐式添加高度约束 (UIView-Encapsulated-Layout-Height) 设置优先级允许 Auto-Layout 优雅地解决这些冲突。见:raywenderlich.com/87975/…
  • 好的,我认为这仅与动态高度有关。我们还注意到宽度完全相同的问题(不同的场景)。尽管变通方法有效,但仍然感觉像是自动布局的错误。你怎么看?
  • 它非常适合用于 tableView 的开始和结束更新。
猜你喜欢
  • 2021-08-20
  • 1970-01-01
  • 2018-12-01
  • 2015-04-05
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-17
相关资源
最近更新 更多