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
Uiview Infinite 360 Degree Rotation Animation
How to Produce an Effect Similar to the iOS 7 Blur View
Wkwebview Not Loading Local Files Under iOS 8
How to Have Stored Properties in Swift, the Same Way I Had on Objective-C
How to Change the Status Bar Background Color and Text Color on iOS 7
Change Paid App to Free But Know If User Previously Purchased It
How to Convert String Date to Nsdate
Draw Text Along Circular Path in Swift For Ios
Can't Get Correct Value of Keyboard Height in Ios8
Append Data to a Post Nsurlrequest
Send and Receive Messages Through Nsnotificationcenter in Objective-C
How to Apply a Perspective Transform to a Uiview
How to Programmatically Get the MAC Address of an Iphone