I have a UITableViewCell with collectionView inside it. constraint are pretty simple leading 0 , trailing 0 , top 10 and bottom 10 and height constraint of UICollection view is 160 . Connected an IBOutlet to height constraint. In cell for row I am updating the heigth constraint.
But getting error in debug
Code of cell for row is
func videoCell(for tableView:UITableView ,with indexPath:IndexPath , videos:[VideoCollectionViewCellConfigure] ) -> VideoTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "VideoTableViewCell", for: indexPath) as! VideoTableViewCell
cell.videoConfigurators = videos
cell.collectionCellClickedBlock = self.videoCollectionCellClicked(_:_:)
if videos.count > 0 {
let video = videos[0]
cell.videoCollectionViewHeightConstraint.constant = video.height
}
cell.videoCollectionView.reloadData()
return cell
}
2018-04-16 12:42:10.815998+0530 CineBee[5280:74417] [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:0x6000006878a0 UICollectionView:0x7f86109c4c00.height
== 180 (active)>",
"<NSLayoutConstraint:0x604000885870 V:[UICollectionView:0x7f86109c4c00]-(10)-| (active, names: '|':UITableViewCellContentView:0x7f8615803ca0 )>",
"<NSLayoutConstraint:0x604000888de0 V:|-(10)-
[UICollectionView:0x7f86109c4c00] (active, names: '|':UITableViewCellContentView:0x7f8615803ca0 )>",
"<NSLayoutConstraint:0x60400088dde0 'UIView-Encapsulated-Layout-Height'
UITableViewCellContentView:0x7f8615803ca0.height == 180.5 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x6000006878a0
UICollectionView:0x7f86109c4c00.height == 180 (active)>
Try this
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var defaultHeight = /*your default height*/
if videos.count > 0 {
let video = videos[0]
return video.height + 10 + 10 // video height + top padding + bottom padding
}
return defaultHeight
}
Also remove the collectionView height constraint from the Interface builder. Now you don't have to set constraint in the cellForItemAtIndexPath.
According to your error report, it seems like the case I was attempting to address in this SO question. If the conflicting constraints contain UIView-Encapsulated-Layout-Height it means the conflict arises during calculating dynamic height based on autolayout. Just lower one of the vertical constraints priority to 999 - if the code works, it's ok and you are good to go.
Related
I am having issues getting rid of a pesky NSAutoresizingMaskLayoutConstraint that is breaking the auto-layout width constraints of some UITextView.
I have a UITableviewCell that contains a text view, and the text view's height is dynamically set based on the content of the text view's text using
self.table.sectionHeaderHeight = UITableView.automaticDimension;
self.table.estimatedSectionHeaderHeight = 200;
This works pretty well when auto-layout is used (I am setting my constraints via the interface and not code). However, I noticed that the widths of the text views are conflicting with NSAutoresizingMaskLayoutConstraint - and the end result is the width constraint on my text view is being removed.
[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.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x6000012ff070 h=--& v=--& UITextView:0x7fde2f09e600'At teenfvfed'.width == 89.5 (active)>",
"<NSLayoutConstraint:0x600001292210 UITextView:0x7fde2f09e600'At teenfvfed'.width == 293 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600001292210 UITextView:0x7fde2f09e600'At teenfvfed'.width == 293 (active)>
The common answer I see online is to add translatesAutoresizingMaskIntoConstraints = false on the text view, but this doesn't have any effect and NSAutoresizingMaskLayoutConstraint remains. Any help would be greatly appreciated to remove this!
Try this:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.text.translatesAutoresizingMaskIntoConstraints = false
cell.setNeedsLayout()
cell.layoutIfNeeded()
}
In my app I have an UITableView with a header created with .xib, this is the class:
class ViewHomeHeader: UIView {
class func instanceFromNib() -> ViewHomeHeader {
return UINib(nibName: "ViewHomeHeader", bundle: nil).instantiate(withOwner: self, options: nil).first as! ViewHomeHeader
}
}
I'm adding it to tableHeaderView:
let viewHomeHeader = ViewHomeHeader.instanceFromNib()
tableView.tableHeaderView = viewHomeHeader
This is the .xib with just one label and its relative constraints.
That's the result if I run on simulator (same on device)
I can't understand why the height is bigger than 21.
With the "Debug View Hierarchy" I can see that is not using the label height but the UIView-Encapsulated-Layout-Height
Console log:
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:0x28079f9d0 UILabel:0x104529b80'Label'.height == 21 (active)>",
"<NSLayoutConstraint:0x2807ac0a0 UILayoutGuide:0x281d9d500'UIViewSafeAreaLayoutGuide'.bottom == UILabel:0x104529b80'Label'.bottom + 17 (active)>",
"<NSLayoutConstraint:0x2807ac140 UILabel:0x104529b80'Label'.top == UILayoutGuide:0x281d9d500'UIViewSafeAreaLayoutGuide'.top + 18 (active)>",
"<NSLayoutConstraint:0x2807ae490 'UIView-Encapsulated-Layout-Height' Jordy.ViewHomeHeader:0x104529790.height == 143 (active)>",
"<NSLayoutConstraint:0x2807ac000 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x281d9d500'UIViewSafeAreaLayoutGuide']-(0)-| (active, names: '|':Jordy.ViewHomeHeader:0x104529790 )>",
"<NSLayoutConstraint:0x28079fc50 'UIViewSafeAreaLayoutGuide-top' V:|-(0)-[UILayoutGuide:0x281d9d500'UIViewSafeAreaLayoutGuide'] (active, names: '|':Jordy.ViewHomeHeader:0x104529790 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x28079f9d0 UILabel:0x104529b80'Label'.height == 21 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
As specified in the documentation:
When assigning a view to this property, set the height of that view to
a nonzero value. The table view respects only the height of your
view's frame rectangle; it adjusts the width of your header view
automatically to match the table view's width.
So you have to set the header size before setting it.
If your header has a height which depends on its content, here is a possible solution:
let header = HeaderView()
let widthConstraint = header.widthAnchor.constraint(equalToConstant: view.bounds.width)
header.translatesAutoresizingMaskIntoConstraints = false
widthConstraint.isActive = true
let targetSize = header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
header.frame.size.height = targetSize.height
widthConstraint.isActive = false
header.translatesAutoresizingMaskIntoConstraints = true
tableView.tableHeaderView = header
Wait viewDidLayoutSubviews() to get the actual size of the view.
If your content is static, simply set its height:
let header = HeaderView()
header.frame.size.height = 30
tableView.tableHeaderView = header
Note that the header's autoresizingMask should not contain flexibleHeight (check your xib). The header should keep the height specified.
You can give lower priority to the bottom spacing constraint and higher priority to height constraint
I've defined my flow layout as follows
internal lazy var layout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 16
layout.sectionInset = UIEdgeInsets(top: layout.minimumLineSpacing, left: layout.minimumLineSpacing , bottom: layout.minimumLineSpacing , right: layout.minimumLineSpacing )
layout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.size.width - (layout.sectionInset.left + layout.sectionInset.right), height: 10)
return layout
}()
In the cell then I set the height for the expected content
override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.height = ceil(size.height)
layoutAttributes.frame = newFrame
return layoutAttributes
}
And it works. I get the cells in the height that I expect them to be, but there is a nasty warning in the console coming up for each cell
[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:0x600003c1e490 V:|-(0)-[UIView:0x7fdc8bead5d0] (active, names: '|':VLCContentCollectionViewCell:0x7fdc8becf8e0 )>",
"<NSLayoutConstraint:0x600003c1ec60 V:[UIView:0x7fdc8bead5d0]-(0)-| (active, names: '|':VLCContentCollectionViewCell:0x7fdc8becf8e0 )>",
"<NSLayoutConstraint:0x600003c4bb60 V:|-(0)-[VLAsyncImageView:0x7fdc8bea20a0] (active, names: '|':UIView:0x7fdc8bead5d0 )>",
"<NSLayoutConstraint:0x600003c43070 V:[VLAsyncImageView:0x7fdc8bea20a0]-(0)-| (active, names: '|':UIView:0x7fdc8bead5d0 )>",
"<NSLayoutConstraint:0x600003c5f340 VLAsyncImageView:0x7fdc8bea20a0.height == 100 (active)>",
"<NSLayoutConstraint:0x600003f8cb90 'UIView-Encapsulated-Layout-Height' VLCContentCollectionViewCell:0x7fdc8becf8e0.height == 10 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600003c5f340 VLAsyncImageView:0x7fdc8bea20a0.height == 100 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
Im pretty sure that it is because of this constraint 'UIView-Encapsulated-Layout-Height' which holds the value for the expected item size of the flow layout, because if I set that to 100 the log message doesn't show up.
However, I'm looking for dynamic cell height, so even if I set it to 100 it will fail at other places.
So my question is if I'm doing something wrong in defining my dynamic cells? Or is there maybe a way to reduce the priority of the estimated cell height, so that it will brake that constraint in case?
I have a .nib for my custom header section for a table view:
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "BillTableSection", bundle: nil)
billTableView.register(nib, forHeaderFooterViewReuseIdentifier: "BillTableSection")
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = billTableView.dequeueReusableHeaderFooterView(withIdentifier: "BillTableSection")
return cell
}
The custom header section works, but whenever I insert a new section, A warning shows up on my console:
2017-10-02 14:56:32.791529+0800 Project[1017:14993] [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:0x61000009f8b0 UIButton:0x7ff359d0d4a0.width == 22 (active)>",
"<NSLayoutConstraint:0x61000009f900 UITextField:0x7ff359d19660.width == UILabel:0x7ff359d17650'$0.00'.width (active)>",
"<NSLayoutConstraint:0x61000009fa90 UITextField:0x7ff359d19660.leading == UIView:0x7ff359d010a0.leadingMargin (active)>",
"<NSLayoutConstraint:0x61000009ed20 H:[UITextField:0x7ff359d19660]-(30)-[UILabel:0x7ff359d17650'$0.00'] (active)>",
"<NSLayoutConstraint:0x61000009f2c0 UIButton:0x7ff359d0d4a0.trailing == UIView:0x7ff359d010a0.trailingMargin (active)>",
"<NSLayoutConstraint:0x61000009ee60 H:[UILabel:0x7ff359d17650'$0.00']-(7)-[UIButton:0x7ff359d0d4a0] (active)>",
"<NSLayoutConstraint:0x61000009f5e0 H:[UIView:0x7ff359d010a0]-(0)-| (active, names: '|':Project.BillTableSection:0x7ff359d0fc70 )>",
"<NSLayoutConstraint:0x61000009f9a0 H:|-(0)-[UIView:0x7ff359d010a0] (active, names: '|':Project.BillTableSection:0x7ff359d0fc70 )>",
"<NSLayoutConstraint:0x61000009ff40 '_UITemporaryLayoutWidth' Project.BillTableSection:0x7ff359d0fc70.width == 0 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x61000009f8b0 UIButton:0x7ff359d0d4a0.width == 22 (active)>
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.
I tried to find the constraints that are not needed and remove them, but the layout I defined will not work on other devices anymore. Is it safe to ignore this warning? I'm not sure how to debug this... Please help!
You should lower the BtnAdd.trailing priority to less than 1000. it looks like autolayout adds a temporary constraint
"<NSLayoutConstraint:0x61000009ff40 '_UITemporaryLayoutWidth' Project.BillTableSection:0x7ff359d0fc70.width == 0 (active)>"
that squishes all the content, so removing that absolute priority will let your content adjust without conflicts.
Also, why is TxtName.width == LblPrice.width? Can't you adjust content hugging priority?
I have a tableViewCell with elements (c - means constraint):
Label: fixed c.height (unimportant)
Label1: multiline, word wrap, c.height >= 20
Label2: multiline, word wrap, c.height >= 16
ImageView: aspectFit, c.height >= 100. Outlet for height
Label: fixed c.height (unimportant)
TableView have set estimatedH = 30 and rowH = Automatic
Compression/hugging priorities wasn't changed - default, bcs all elements have equal priority
in cellForRow I set Label1 and Label2 text (2 lines and 3 lines accordingly). Also I call SDWebImage method sd_setImage for imageView with completion. In completion I set imageView height, according to formula:
newHeight = (cell.newsImageView.bounds.width / image.size.width) * image.size.height
But as result, my Labels shows maximum 2 lines of text and imageView has an incorrect height. After tableView reloading (pull-to-refresh) or for new dequed cells all Ok, but for visible - not good.
I've tried to prefetch images using SDWebImagePrefetcher and reload table in its completion, but this don't help
Any ideas how to fix this behaviour?
Upd 05.04.17
Here is log stack about constraint conflict. Maybe it can help to analyze issue.
(
"<NSLayoutConstraint:0x797a1ec0 V:[UILabel:0x7b06b990'22.03.2017 '(16)]>",
"<NSLayoutConstraint:0x797c7250 V:[UIImageView:0x797e6560(214.2)]>",
"<NSLayoutConstraint:0x797ca430 V:[UILabel:0x797c7900'\U0427\U0418\U0422\U0410\U0422\U0418 \U041d\U041e\U0412\U0418\U041d\U0423'(20)]>",
"<NSLayoutConstraint:0x797d7ac0 V:|-(16)-[UILabel:0x7b06b990'22.03.2017 '] (Names: '|':UIView:0x7b0810d0 )>",
"<NSLayoutConstraint:0x797d2ac0 V:[UILabel:0x7b06b990'22.03.2017 ']-(0)-[UILabel:0x797c40a0'\U0406\U043d\U0444\U043e\U0440\U043c\U0430\U0446\U0456\U044f \U0434\U043b\U044f \U0430\U0431\U043e\U043d\U0435\U043d\U0442\U0456\U0432 ...']>",
"<NSLayoutConstraint:0x797d2b80 V:[UILabel:0x797c40a0'\U0406\U043d\U0444\U043e\U0440\U043c\U0430\U0446\U0456\U044f \U0434\U043b\U044f \U0430\U0431\U043e\U043d\U0435\U043d\U0442\U0456\U0432 ...']-(0)-[UILabel:0x797c9090'\U0417 1 \U043a\U0432\U0456\U0442\U043d\U044f 2017 \U0440\U043e\U043a\U0443 \U043f\U0440\U043e\U0432...']>",
"<NSLayoutConstraint:0x797d7c70 V:[UILabel:0x797c9090'\U0417 1 \U043a\U0432\U0456\U0442\U043d\U044f 2017 \U0440\U043e\U043a\U0443 \U043f\U0440\U043e\U0432...']-(10)-[UIImageView:0x797e6560]>",
"<NSLayoutConstraint:0x797d7d00 V:[UIImageView:0x797e6560]-(10)-[UILabel:0x797c7900'\U0427\U0418\U0422\U0410\U0422\U0418 \U041d\U041e\U0412\U0418\U041d\U0423']>",
"<NSLayoutConstraint:0x797d7d30 V:[UILabel:0x797c7900'\U0427\U0418\U0422\U0410\U0422\U0418 \U041d\U041e\U0412\U0418\U041d\U0423']-(10)-| (Names: '|':UIView:0x7b0810d0 )>",
"<NSLayoutConstraint:0x797d8160 V:[UIView:0x7b0810d0]-(5)-| (Names: '|':UITableViewCellContentView:0x7b151eb0 )>",
"<NSLayoutConstraint:0x797d8190 V:|-(5)-[UIView:0x7b0810d0] (Names: '|':UITableViewCellContentView:0x7b151eb0 )>",
"<NSLayoutConstraint:0x797dacb0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7b151eb0(274)]>"
)
Upd: Sample project
You're setting the estimatedH = 30 but you have actually much more contents
20 + 16 + 100 = 136 which is much more than your estimation
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 150
if you want to update specific cells after downloading your data then you can call the update table view
self.tableview.beginUpdates()
tableview.reloadRows(at: [indexPath], with:.bottom)
self.tableview.endUpdates()
reloadRows has enum for the options which you can access those with dot notation which I have selected .bottom but you can select from the enum which ever matches your need
Updated: Sample Project