What Is Nslayoutconstraint "Uiview-Encapsulated-Layout-Height" and How to Go About Forcing It to Recalculate Cleanly

Adjusting custom Tableviewcell - NSLayoutConstraint conflict. UIView-Encapsulated-Layout-Height

Table views can end up with non-whole-number heights due to the way cell separators are rendered.

So, on a device with @2x screen scale, your comicsUIVIew height will end up at 310.5 ... on a @3x device, it will be 310.333

If that's acceptable, you can avoid the auto-layout complaints by changing the Priority on your height constraint:

    //constraints.append(comicsUIVIew.heightAnchor.constraint(equalToConstant: 310))

let hc = comicsUIVIew.heightAnchor.constraint(equalToConstant: 310)
hc.priority = .defaultHigh
constraints.append(hc)

If you need comicsUIVIew to be exactly 310 points, you can add a clear "spacer" view (or a UILayoutGuide) below comicsUIVIew, giving it a height constraint of 0.0 with priority of .defaultHigh. It will end up being 0.5 or 0.333 points tall.

Or... set tableView.separatorStyle = .none, and design your cell to have a "bottom border line" to simulate the separator if desired.

UIView-Encapsulated-Layout-Height constraint issue in Table View

Not sure why the issue is happening, but

tableView.beginUpdates()
tableView.endUpdates()

fixed it somehow.

Full code

class ViewController: UITableViewController {

override func viewDidLoad() {
super.viewDidLoad()

// https://stackoverflow.com/a/27148268/14016301

tableView.estimatedRowHeight = 2.0
tableView.rowHeight = UITableView.automaticDimension
}

override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

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

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)

cell.textLabel?.text = "AAAA"
let h = cell.contentView.heightAnchor.constraint(equalToConstant: 30)
h.priority = .defaultHigh
h.isActive = true

_ = Timer.scheduledTimer(withTimeInterval: 2, repeats: false, block: { _ in
h.constant = 500
self.tableView.beginUpdates()
self.tableView.endUpdates()
})

return cell
}

}

Custom TableViewCell triggers NSLayoutConstraint error 'UIView-Encapsulated-Layout-Height'

First, you keep neglecting to set your subviews' translatesAutoresizingMaskIntoConstraints to false. That's important. (Perhaps snapkit does that for you, however. I don't know.)

Second — and this is the big point — what you're doing is not how you size a variable height cell from the inside out. You do not change an absolute height constraint, as your code is doing. The sizing is based ultimately on the intrinsic content size of the subviews. Some subviews might have absolute heights, certainly, but ultimately there must be at least one with an intrinsic content size. That is the size that you are able to change dynamically in order to determine the height of a cell.

That is why, for example, a cell containing a UILabel is so easy to use with dynamic row heights. It has an intrinsic content size.

The intrinsic content size does not conflict with the built-in height of the cell (the UIView-Encapsulated-Layout-Height in your console dump); it supplements it (when the runtime calls systemLayoutSizeFitting(UILayoutFittingCompressedSize) behind the scenes, which is how automatic variable row heights works).

If you use custom subviews with an implementation of intrinsicContentSize, and if setting your model value in the cell triggers a call to invalidateIntrinsicContentSize, your example will work perfectly with no complaints in the console.

Here is an example of such a custom view:

class MyView : UIView {
var h : CGFloat = 200 {
didSet {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
return CGSize(width:300, height:self.h)
}
}

When this is a subview of your cell's content view, setting this view's h in cellForRow sizes the cell's height correctly.

For example, let's suppose our cell's content view has just one subview, v, which is a MyView. Then:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MyCell
let even = indexPath.row % 2 == 0
cell.v.backgroundColor = even ? .red : .green
cell.v.h = even ? 40 : 80 // triggers layout!
return cell
}


Related Topics



Leave a reply



Submit