Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView when changing constraint which effects height of cell after dequeueing, end up with broken constraints

This code block tries to get to the heart of the problem. If, after dequeuing a cell (via configure), the constraints are changed so that the cell height is changed, then you end up with a broken constraints warning (Unable to simultaneously satisfy constraints...). However, it displays correctly.

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,
]

Error message is...

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.
like image 907
Nick McConnell Avatar asked Nov 28 '25 00:11

Nick McConnell


1 Answers

Set your constraints' priorities to 999. Just like now, it will display correctly.

like image 120
Stefan Arambasich Avatar answered Nov 30 '25 14:11

Stefan Arambasich



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!