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
Related
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 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.
I have a stack view that look like the figure below:
So I change the height of the image programmatically to make it fit the image that download from my server,if dont have image,the height constraints of image will set to be zero.
Here is my code to doing so:
let imageUrl = URL(string :imageString)
if let data = try? Data(contentsOf: imageUrl!)
{
guard let actualImage: UIImage = UIImage(data: data) else{
print("No image!")
ImageView.image = nil
defaultImageHeightContrainst = ImageHeightContrainst.constant
ImageHeightContrainst.constant = 0
layoutIfNeeded()
return
}
let imageHeight = actualImage.size.height * actualImage.scale
print("imageHeight = \(imageHeight)")
defaultImageHeightContrainst = ImageHeightContrainst.constant
ImageHeightContrainst.constant = imageHeight
layoutIfNeeded()
//here display the image to the imageview
ImageView.kf.setImage(with: imageUrl)
}
With the code above,the image height is scale according to actual image height which download from internet.If dont have image,the "image" part also set to 0 already.
This is what I expected,but now I face an error below whenever the "image" height become taller in order to fit the actual image height
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:0x6080002868b0 UIImageView:0x7f9cbae59240.height == 50 (active)>",
"<NSLayoutConstraint:0x608000286bd0 UIView:0x7f9cbae5ad80.height == 1 (active)>",
"<NSLayoutConstraint:0x608000286d10 UIImageView:0x7f9cbae5b440.height == 458 (active)>",
"<NSLayoutConstraint:0x608000286f90 UIView:0x7f9cbae5bb50.height == 1 (active)>",
"<NSLayoutConstraint:0x6080002871c0 V:|-(0)-[UILabel:0x7f9cbae5b160] (active, names: '|':UIStackView:0x7f9cbae5af60 )>",
"<NSLayoutConstraint:0x608000287350 V:[UILabel:0x7f9cbae5b160]-(10)-[UIImageView:0x7f9cbae5b440] (active)>",
"<NSLayoutConstraint:0x6080002873a0 V:[UIImageView:0x7f9cbae5b440]-(10)-[UIStackView:0x7f9cbae5b670] (active)>",
"<NSLayoutConstraint:0x608000287580 V:[UIStackView:0x7f9cbae5b670]-(10)-[UIView:0x7f9cbae5bb50] (active)>",
"<NSLayoutConstraint:0x6080002875d0 V:[UIStackView:0x7f9cbae5c0f0]-(0)-| (active, names: '|':UIStackView:0x7f9cbae5af60 )>",
"<NSLayoutConstraint:0x608000287670 V:[UIView:0x7f9cbae5bb50]-(10)-[UIStackView:0x7f9cbae5c0f0] (active)>",
"<NSLayoutConstraint:0x6080002877b0 V:|-(10)-[UIImageView:0x7f9cbae59240] (active, names: '|':UITableViewCellContentView:0x7f9cbae5a0c0 )>",
"<NSLayoutConstraint:0x6080002878f0 V:[UIImageView:0x7f9cbae59240]-(8)-[UIView:0x7f9cbae5ad80] (active)>",
"<NSLayoutConstraint:0x6080002879e0 V:[UIStackView:0x7f9cbae5af60]-(10)-| (active, names: '|':UITableViewCellContentView:0x7f9cbae5a0c0 )>",
"<NSLayoutConstraint:0x608000287a80 V:[UIView:0x7f9cbae5ad80]-(8)-[UIStackView:0x7f9cbae5af60] (active)>",
"<NSLayoutConstraint:0x608000288c00 'UISV-canvas-connection' UIStackView:0x7f9cbae5c0f0.top == _UILayoutSpacer:0x6080001cd5c0'UISV-alignment-spanner'.top (active)>",
"<NSLayoutConstraint:0x608000288ca0 'UISV-canvas-connection' V:[_UILayoutSpacer:0x6080001cd5c0'UISV-alignment-spanner']-(0)-| (active, names: '|':UIStackView:0x7f9cbae5c0f0 )>",
"<NSLayoutConstraint:0x608000289970 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7f9cbae5a0c0.height == 476.5 (active)>"
)
Before asking,I already checked all my other constraints,which is all set correctly.I even disable all the code that can change the height of "image",once disable,there is no problem.The error only occurred when I intend to change the height.
I even tried to add ImageView.translatesAutoresizingMaskIntoConstraints = false before layoutIfNeeded(),but the error is still exist.
So what is the correct way to change the height of image in order to fit the actual image download from server?
Considering that the last constraint says
"<NSLayoutConstraint:0x608000289970 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7f9cbae5a0c0.height == 476.5 (active)>"
I assume you are using stackView inside of a UITableViewCell to implement automatic height cells in a tableView. If my assumption is correct, then the problem is not with the stackView, nor with the imageView, but with the way UITableView works with UITableViewAutomaticDimension and Autolayout. If the layout works as you expect, and the warning is the only thing that bugs you, then read following.
Therefore it seems to me that this is a result of an known "bug" - there is a collision of the height set by the tableView and the height calculated by the autolayout. When rendering the cell, the tableView first applies the default height, calculates the autolayout height, and then use the latter - at least it seems so. See my question. The constraint mentioned above ('UIView-Encapsulated-Layout-Height') is the one applied by the UITableView that later goes away.
That means that the constraints you are using are probably OK. Just set one of the constraints defining height to priority = 999 (so that until it deactivates the default height constraint it won't cause any conflict). In the end, it will result in using your constraint anyway, so it will not cause any layout trouble.
E.g., if you constrain the stackView to fit the cell's contentView, set the stackView.bottomAnchor to contentView.bottomAnchor just with the priority set to 999. If you did the layout programmatically, this might be your solution:
let bottomConstraint = tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
bottomConstraint.priority = UILayoutPriority(rawValue: 999)
NSLayoutConstraint.activate([
// rest of the constraints
stackView.topAnchor.constraint(equalTo: contentView.topAnchor),
stackView.leftAnchor.constraint(equalTo: contentView.leftAnchor),
stackView.rightAnchor.constraint(equalTo: contentView.rightAnchor),
bottomConstraint,
])
If you do the layout in storyboards, just select appropriate constraint in the storyboards, and in the attributes inspector set its priority to 999 (for example):
A collection view is placed in the upper part of the screen. The collection view is horizontal and has one row.
The row can contain multiple collection view cells.
Each cell inside has UIImageView. The UIImageView is meant to contain an UIImage.
The UIImage is a photo. A photo might be of a different size, but inside the collection view cell it has to be squared with aspect ratio 1:1.
The problem is making the collection view cell to be of square size, where the side of the square should be equal to the height of the collectionView. And the UIImageView should take whole space of the collection view cell making the UIImage squared.
The UIImageView has constraints set ratio 1:1; and the top, leading, and bottom of collection cell.
The collection cell has its size calculated programatically:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let size = collectionView.bounds.size.height
return CGSize(width: size, height: size)
}
I get the following error in the debugger:
[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:0x6180000968f0 h=--& v=--& UIView:0x7f8c3f61e940.width == 217 (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x618000096990 h=--& v=--& UIView:0x7f8c3f61e940.height == 100 (active)>",
"<NSLayoutConstraint:0x618000096030 UIImageView:0x7f8c3f61eae0.width == UIImageView:0x7f8c3f61eae0.height (active)>",
"<NSLayoutConstraint:0x618000096120 H:[UIImageView:0x7f8c3f61eae0]-(0)-| (active, names: '|':UIView:0x7f8c3f61e940 )>",
"<NSLayoutConstraint:0x618000096170 V:[UIImageView:0x7f8c3f61eae0]-(0)-| (active, names: '|':UIView:0x7f8c3f61e940 )>",
"<NSLayoutConstraint:0x6180000961c0 H:|-(0)-[UIImageView:0x7f8c3f61eae0] (active, names: '|':UIView:0x7f8c3f61e940 )>",
"<NSLayoutConstraint:0x618000096210 V:|-(0)-[UIImageView:0x7f8c3f61eae0] (active, names: '|':UIView:0x7f8c3f61e940 )>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x618000096030 UIImageView:0x7f8c3f61eae0.width == UIImageView:0x7f8c3f61eae0.height (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.
How to make it work?
You don't need both the aspect ratio constraint and the right constraint. One is enough. But, logically if you had both they shouldn't conflict if your size calculations is correct.
Your calculation looks good. Therefore, the thing in mind that could effect your calculations is the (header size, footer size, spacing insets)
Another thing that could affect this is reloading collection view data
on viewDidLoad before the uiviews complete layouting.
I am trying to use AutoLayout to configure the subviews in my table view cells and in the ideal case would like the table view cell to be just as high as necessary to contain all the subviews. However, that does not seems to be possible, since the height for a cell is determined before the cell is actually created.
So, for now, I just looked at the constraints I set up and calculated the total height needed to contain everything and set that in the storyboard as the row height for this specific TableViewCell prototype cell and I also return this height in the tableView:heightForRowAtIndexPath: method.
Now, my table view cell looks like this (screenshot from storyboard):
There are two constraints which don't have a size shown, they both have the size 10 (the button-top-container-view and the distance between the slider and the label in the middle).
Going from top-to-bottom the following distance occur:
10 (distance)
50 (height of button)
20 (distance)
20 (height of label)
10 (distance)
30 (height of slider)
20 (distance)
leading to a total height of 160.
That's exactly what I have set in the inspector of this cell:
but as you can see from the first screenshot, Interface builder complains that the constraints are conflicting (that's why they are displayed in red). IB is satisfied if I set the height to 161, but that is wrong.
Also, if I do, I get exceptions at runtime due to conflicting constraints:
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)
(
"<NSLayoutConstraint:0x8d80240 V:[UISlider:0x8d81190(30)]>",
"<NSLayoutConstraint:0x8d833e0 V:[UILabel:0x8d83300(20)]>",
"<NSLayoutConstraint:0x8d83750 V:[UIButton:0x8d83600(50)]>",
"<NSLayoutConstraint:0x8d85050 V:|-(10)-[UIButton:0x8d83600] (Names: '|':UITableViewCellContentView:0x8d80ef0 )>",
"<NSLayoutConstraint:0x8d851d0 V:[UILabel:0x8d83300]-(10)-[UISlider:0x8d81190]>",
"<NSLayoutConstraint:0x8d85200 V:[UISlider:0x8d81190]-(20)-| (Names: '|':UITableViewCellContentView:0x8d80ef0 )>",
"<NSLayoutConstraint:0x8d85320 V:[UIButton:0x8d83600]-(20)-[UILabel:0x8d83300]>",
"<NSAutoresizingMaskLayoutConstraint:0x8d8b7a0 h=--& v=--& V:[UITableViewCellContentView:0x8d80ef0(161)]>"
)
the last one is the only one I did not explicitly set, but it seems to be generated from the row-height setting in the storyboard, since my tableView:heightForRowAtIndexPath: method returns 160:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == self.fetchedItemSetsController.fetchedObjects.count - 1)
{
return 160;
}
return 44;
}
(at the moment I always want the last cell to be the large and special one)
So, okay, IB complains when I set the row height to 160, but when I set it to 161 the runtime complains. So I tried ignoring IB and set the row height to 160 in the storyboard as well (as seen in the second screenshot). In that case, I get the same error message with a tiny difference:
"<NSLayoutConstraint:0x17809ce80 V:[UISlider:0x125613660(30)]>",
"<NSLayoutConstraint:0x1782814f0 V:[UILabel:0x125615100(20)]>",
"<NSLayoutConstraint:0x178281a90 V:[UIButton:0x125615b50(50)]>",
"<NSLayoutConstraint:0x178281b80 V:|-(10)-[UIButton:0x125615240] (Names: '|':UITableViewCellContentView:0x178161980 )>",
"<NSLayoutConstraint:0x178281c20 UIButton:0x1256157b0.height == UIButton:0x125615240.height>",
"<NSLayoutConstraint:0x178281d10 UIButton:0x1256157b0.height == UIButton:0x125615980.height>",
"<NSLayoutConstraint:0x178281e00 V:[UILabel:0x125615100]-(10)-[UISlider:0x125613660]>",
"<NSLayoutConstraint:0x178281e50 V:[UISlider:0x125613660]-(20)-| (Names: '|':UITableViewCellContentView:0x178161980 )>",
"<NSLayoutConstraint:0x178281f40 UIButton:0x125615980.height == UIButton:0x125615b50.height>",
"<NSLayoutConstraint:0x178282030 V:[UIButton:0x125615240]-(20)-[UILabel:0x125615100]>",
"<NSAutoresizingMaskLayoutConstraint:0x178283340 h=--& v=--& V:[UITableViewCellContentView:0x178161980(159.5)]>"
The constraint for the height of the table view cell is now 159.5 instead of 160. I also encountered it as 160.5 before, with the same storyboard setting, but I am not sure where that came from.
So, first I thought it was just a display bug in IB, but now it actually seems to be creating the wrong constraint. It creates a constraint with 160.5 (or 159.5) instead of the 160 I specified. Why is that? What can I do about it?
Btw: The cells seems to be displayed correctly, but then again I doubt I would be able to see a 0.5 point difference. Mainly, I would like to get rid of the exceptions, since they make the debugging much harder, but I would also like to know what is going on here.
UPDATE:
The 159.5 is not JUST due to the storyboard setting I just noticed, it is a strange combination of the storyboard setting and the return value of the tableView:heightForRowAtIndexPath:.
Here are a few examples of the height of the generated autoresizingmasklayoutconstraint depending on the storyboard height (sb) setting and the return value of the tableView:heightForRowAtIndexPath: method (method). In all cases, the constraints of the subview should lead to a height of 160 and are not changed.
160 (sb) & 160 (method): 159.5 (constraint)
161 (sb) & 160 (method): 159.5 (constraint)
160 (sb) & 161 (method): 160.5 (constraint)
162 (sb) & 161 (method): 162 (constraint)
161 (sb) & 162 (method): 161 (constraint)
162 (sb) & 162 (method): 162 (constraint)
So I thought, okay, for (6.) they all agree, I will just make the label's height 22, so the total height according to the subviews will be 162 as well. Result:
6a. 162 (sb) & 162 (method), 162 (total height of subviews): 161.5 (constraint)
WHAT?!
Any ideas what's happening here?
Update 2
I provided an example project that reproduces the issue on Github.
Separator is messing with the height of the contentView, either it should be disabled (and replaced with custom one if required) so that the contentView height matches the height of the cell or the constraints should be changed to more flexible considering that the contentView height may mismatch the height of the cell. Doing both would be even better.
Now that you've uploaded the example to github, I was able to see that the constraints were in fact over-determined. There was too much "this is equal to that", esp. in the area of vertical spacings/heights. I simplified the constraints, and was able to change to your code to this:
-(CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
{
return 44;
} // else
UITableViewCell* cell =
[tableView dequeueReusableCellWithIdentifier:#"LargeCell"];
CGSize sz =
[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingExpandedSize];
return sz.height;
}
If I'm not mistaken, that's exactly the sort of thing you are after, i.e. to let the constraints themselves dictate the height of the cell.