estimatedRowHeight with multiple lined label causing clipping of cell - ios

Some background : I have a nested tableView in which I can have different types of cell ranging from map to images to key-value pair and more so I had to work with nested tableView which is hard to be achieved by section-row combination
I am using auto-resizing cells.
In my parentTableView I have set
parentTableView.rowHeight = UITableViewAutomaticDimension
parentTableView.estimatedRowHeight = 200
In my childTableView , I have set
childTableView.rowHeight = UITableViewAutomaticDimension
childTableView.estimatedRowHeight = 68.0
Here 68.0 is my cell size which is a custom XIB having two UILabel in vertical sort of orientation. Now when the labels are not multiple line, the tableView is appearing fine . But when i add multiple lines to the labels, the cells are getting clipped
But when I increase the estimatedRowHeight to say a greater value like 80, it is not getting clipped but displaying the content AND add some extra white space at the end
What I believe is happening is that it looks at the estimatedRowHeight value and number of cells that are to be displayed and calculates the parent cell size as per that . And when multiple lined label occurs it increases the size of the cell but the parent cell size has already been defined so it gets clipped
Can anyone please help me out i have tried a lot of fix but nothing is working.

First of all, I would like to suggest that please avoid the nested tableView concept. You may facing glitch issue while reloading it and when data will be huge, it may cause UI blockage.
Coming to Solution,
Please try the following solution:
- Add constraints to each element as per your requirement except last UILabel.
- Add top and bottom constraints (compulsory) with any other constraints (if you need). It will help the cell to understand the run time height of that cell.
- In tableViewCell(_ heightforrow) method, put the height as return
UITableViewAutomaticDimension
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}

Related

Configuring TableView with automatic cell height results in no cells displayed

My goal is to use UITableViewAutomaticDimension to show cells with dynamic heights in my TableView. At the moment, no cells show up in my tableview after enabling UITableViewAutomaticDimension.
Here is my current configuration:
I am using a custom cell class, called FeedCell
FeedCell has a view called ForegroundContainerView, which has been configured as such where all sides are pinned.
I have also tried to pin the ContentView of the cell, but was unable to:
Lastly, I have the following in viewDidLoad:
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 112.0
(I also deleted the default function func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
If I don't use UITableViewAutomaticDimension, the cells appear normally, confirming that the data is fed into the tableview correctly.
What am I doing wrong? Any pointers much appreciated.
I think your constraints are ambiguous. You are asking UIKit to automatically size your cell (UITableViewAutomaticDimension), but the "Foreground Container View" does not have a defined height...it is only constrained to the cell itself (which also doesn't have a defined height!).
So you probably have some kind of ambiguous constraint warning in the console since the system doesn't know what to do, or it's possible your "Foreground Container View" is defaulting to a height of 0.0 meaning your table cell height is about 10.5 (0.0 + your constrained spacing). You didn't include a screenshot of what actually shows in the simulator, so I'm just guessing.
Give your "Foreground Container View" some content or explicitly constrain it's height to something you will be able to see (ex. 200px). Also I recommend you give it a background color so you can actually see it's height on your screen.
To get automatic cell sizing with actual cell content, you should constrain views (labels, images, whatever else) inside your "Foreground Container View" (or if you want, inside the cell's content view directly).
There must be both a top spacing and bottom spacing constraint between the anticipated tallest subviews (labels, images, etc.) and the container.

How to have multiple cell sizes in a dynamic tableView in swift?

I want to have cells with different sizes in a tableView but all after build and running the app I see that all cells have same size and the bigger cell gets cropped and its content become incomplete. I set sizes in attribute inspector.
it is as simple as implementing:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(#your desired size#)
}
just use a switch/case in this function and work with indexPath.row. You can also use UITableViewAutomaticDimension for automatic sizing
EDIT:
According to the title, description of this question, and the picture provided I guessed 3 possible situations and tried to cover all in my short answer above. But as Rikh thought it was not the situation, I am going to clear things up.
Remember that for dynamic rows you must fix all the views in their place in autolayout, meaning you have to set constraints from top of the scene to the bottom and left to the right.
Possible Situations are:
Situation 1:
You have 2 different cells in your table and you know their sizes (first row is type1 and other cells are type2).
In this situation you just need to add an if clause or switch/case in the function I mentioned like this (Imagining that first row is 88 point and the rest are 44 point):
return indexPath.section == 0 ? CGFloat(88.0) : CGFloat(44.0)
Situation 2:
Your first row is fixed size and the rest are dynamic.
After you set correct constraints on your cells, in viewDidLoad add tableView.estimatedRowHeight = CGFloat(44.0) in which the estimatedRowHeight is the minimum possible height for your cells. Then you can write your code like this:
return indexPath.section == 0 ? CGFloat(88.0) : UITableViewAutomaticDimension
Situation 3:
The height of your rows are all dynamic and you want all of them to expand by themselves. In this situation you do not need the function I mentioned at all. Actually if you have it in your code you must remove it.
In this situation go on and add this code to viewDidLoad of your code (Imagining minimum possible height of your cells is 44 point):
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = CGFloat(44.0)
Again remember that it is really important to set all of your constraints correctly for this to work. An example: I guess "detail" label is the one that will make your row's height grow and title is fixed size, so these are the constraints you need on your "detail" label: set its height to greater than equal (>=) 21, set it to align vertically in middle of superview (by setting "Vertically in Container" constraint in your storyboard), set horizontal space to "title" label, set trailing space to superview, set number of lines to 0 which makes it expand infinitely, and finally set the line break attribute to "word wrap". In this situation your title must have specific width constraint or you'll get an error.
P.S.: Actually now that I am writing this I can imagine another situation in which your "title" label's width is also dynamic. This will make your tableView really ugly but if this is your situation, you need to set "content hugging" and "Content Compression" on your labels, which is described Here (CHCR)
Define auto layout constraints for your prototype cell.
Specify the estimatedRowHeight of your table view
Set the rowHeight of your table view to UITableViewAutomaticDimension
Example
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
If you are using Autolayout everything will work as expected.
Sample demo you will get here.
https://www.dropbox.com/s/ug9xu0yfcua902o/SelfSizingDemo.zip?dl=0
https://www.raywenderlich.com/129059/self-sizing-table-view-cells
Does each subview have constraints that pin all of their sides?
Are there constraints going from the top to the bottom of the contentView?
Are You setting tableView.rowHeight = UITableViewAutomaticDimension?

In tableview i have 4 static cells. How do i make row height automatically calculated to fit the label inside and one manually

So i have four sections and one cell in each one of the sections in my static tableview. One of them is displaying a picture and for that one i manually calculate the ration and multiply it by the width and that way i get the correct height. I do that using the "heightForRowAtIndexPath".
I also have three other cells and each one has a label in it. The labels content is different each time since i'm segueing to it from a different cell so sometimes the cell should be big enough for 1 row of text and sometimes for more. How do i calculate/set that to happen automatically?
Also in my storyboard i have the constrains for the label set to be 8 point away from the right left and top, thats all the constrains that are on the label. I already tried setting the tableView.rowHeight to UITableViewAutomaticDimensions but that doesn't do anything. The rows just stay at the same height as they were set in the "heightForRowAtIndexPath" or the same as in the storyboard if that function is not implemented. Been trying to solve that for probably more then an hour now and still cant figure it out. Thanks for the help. Also i'm doing all of this in swift.
If you implement heightForRowAtIndexPath it will also override any value for the table view's rowHeight. So, in heightForRowAtIndexPath return UITableViewAutomaticDimension, and do the same in estimatedHeightForRowAtIndexPath too.
As long as your cell has a solid Auto Layout configuration, that's all it takes to make auto-sizing cells work.

UITableView Scroll Bar changes in size as user scrolls

I have a UITableView where the size of each cell is different (it depends on the amount of content needed to be displayed).
As a result (or at least I think as a result), the vertical scroll bar is initially small when the user first starts scrolling. As the user continues to scroll, the scroll bar grows, reaching its correct length when the user makes it to the last cell.
Does anyone have any ideas on how to fix this (I am using Swift and Xcode 7.1.1)?
That usually happens when the estimated row height you give to the UITableView is always larger than the actual row height.
Since you don't say how you're determining the height of your rows, I'm going to assume you're using auto layout.
You either want to set the estimatedRowHeight to a value that is closer to the average row height.
tableView.estimatedRowHeight = 100
The other option is to use the UITableViewDelegate method to return an estimated height for each row that is closer to the actual value.
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let estimatedHeight = // some fast calculation based on the data for the row
return estimatedHeight
}
The first option is go for if your rows are generally the same size with little variation. The second option is better if to row size can have a lot of variation or you just have no way of knowing what a good average will be.

Detected a case where constraints ambiguously suggest a height of zero

After updating to Xcode 6.1 beta 2 when I run my app that contains tableview cells, the debug assistant says:
Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
Before, when I used Xcode 5 on this project, I would get a few errors but those have gone away since I upgraded. I have no other errors or warnings now. I have already tried adjusting the sizes of all the tableview cells and also tried using standard height but I still get the same warning:
Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
I have also read through all similar topics on this but none of their solutions help. When I test the app with the simulator, the app runs fine except the pictures that are supposed to be in the tableView cells aren't there.
You're encountering the side effect of a fantastic new feature in iOS8's Tableviews: Automatic Row Heights.
In iOS 7, you either had rows of a fixed size (set with tableView.rowHeight), or you'd write code to calculate the height of your cells and you'd return that in tableView:heightForRowAtIndexPath. Writing code for the calculation of a cell's height could be quite complex if you had numerous views in your cell and you had different heights to consider at different font sizes. Add in Dynamic Type and the process was a pain in the ass.
In iOS 8, you can still do the above, but now the height of the rows can be determined by iOS, provided that you've configured the content of your cell using Auto Layout. This is huge benefit for developers, because as the dynamic font size changes, or the user modifies the text size using Accessibility Settings, your UI can be adaptive to the new size. It also means if you have a UILabel that can have multiple rows of text, your cell can now grow to accommodate those when the cells needs to, and shrink when it does not, so there isn't any unnecessary whitespace.
The warning message you're seeing is telling you that there aren't enough constraints in your cell for Auto Layout to inform the tableview of the height of the cell.
To use dynamic cell height, which, along with the techniques already mentioned by other posters, will also get rid of this message, you need to ensure your cell has sufficient constraints to bind the UI items to the top and bottom of the cell. If you've used Auto Layout before, you are probably accustomed to setting Top + Leading constraints, but dynamic row height also requires bottom constraints.
The layout pass works like this, which occurs immediately before a cell is displayed on screen, in a just-in-time manner:
Dimensions for content with intrinsic sizes is calculated. This includes UILabels and UIImageViews, where their dimensions are based on the text or UIImages they contain, respectively. Both of these views will consider their width to be a known (because you've set constraints for trailing/leading edges, or you set explicit widths, or you used horizontal constraints that eventually reveal a width from side to side). Let's say a label has a paragraph of text ("number of lines" is set to 0 so it'll auto-wrap), it can only be 310 points across, so it's determined to be 120pt high at the current font size.
The UI is laid out according to your positioning constraints. There is a constraint at the bottom of the label that connects to the bottom margin of the cell. Since the label has grown to be 120 points tall, and since it's bound to the bottom of the cell by the constraint, it must push the cell "down" (increasing the height of the cell) to satisfy the constraint that says "bottom of the label is always standard distance from the bottom of the cell.
The error message you reported occurs if that bottom constraint is missing, in which case there is nothing to "push" the bottom of the cell away from the top of the cell, which is the ambiguity that's reported: with nothing to push the bottom from the top, the cell collapses. But Auto Layout detects that, too, and falls back to using the standard row height.
For what it's worth, and mostly to have a rounded answer, if you do implement iOS 8's Auto Layout-based dynamic row heights, you should implement tableView:estimatedHeightForRowAtIndexPath:. That estimate method can use rough values for your cells, and it'll be called when the table view is initially loaded. It helps UIKit draw things like the scrollbar, which can't be drawn unless the tableview knows how much content it can scroll through, but does't need totally accurate sizes, since it's just a scrollbar. This lets the calculation of the actual row height be deferred until the moment the cell is needed, which is less computationally intensive and lets your UITableView be presented quicker.
Three things have managed to silence this warning so far. You can pick up the most convenient for you. Nothing pretty though.
To set up default cell's height in viewDidLoad
self.tableView.rowHeight = 44;
Go to storyboard and change row height on your tableview to something different than 44.
To implement tableview's delegate method heightForRowAtIndexPath
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44;
}
Weird.
To resolve this without a programmatic method, adjust the row height of the table view in the Size Inspector from the storyboard.
I had this problem after creating a custom UITableViewCell and adding my subviews to the cell instead of its contentView.
This is an autolayout issue. Make sure that your subviews have all the constraints. For me, the bottom constraint was missing for the Title Label in the cell. When I added that, the warning went away and everything showed up perfectly.
Just enable Self-Sizing Table View Cells
tableView.estimatedRowHeight = 85.0
tableView.rowHeight = UITableViewAutomaticDimension
& make sure you added constraints on all sides of UITableViewCell as-
Example Link 1
Example Link 2
If u are using static cell or dynamic cell ,simply add some row height to table view in inspector table and uncheck the automatic to the right side of row height ,that's it u will stop getting this warning .
I got this warning today. Here is what made it disappear for me(in interface builder)
1.Set the row height field for the table view to something other than 44
2 Set the row height field for the tableView cell to something other than 44
I did not have to make any changes in code
In my case, I was building the cell programmatically and kept getting this error.
I was adding the subviews and constraints in the UITableViewCell's init method like this:
addSubview(rankingLabel)
addConstraints(cellConstraints)
I solved the issue by adding them to the cell's contentView instead:
contentView.addSubview(rankingLabel)
contentView.addConstraints(cellConstraints)
Set the estimated row height to zero and the warning disappears:
If you have created a Custom tableViewCell for tableView, make sure you have given both bottom and top constraints to you cells,
you could also get this message if your subviews inside custom cells are aligned in center Y which wouldnt pop any error message but would mess up with identifying height of row for tableview in turn like in Image I have attached , here we have both top and bottom constraints
When you create a Custom Cell for tableView you must specific row height or top and bottom constraints for you custom cell's subviews inside cell (e.g. label in custom cell like in below image)
But if this doesn't work you can try setting row height for your cell instead of being automatic like in this image
But be sure if you turn that automatic tick off you have to adjust your row size for changes programmatically which could have been done automatically
I got this Warning today All I did is just added one extra line to my code
tableView.rowHeight = 200;
add this line of code inside the
func tableView(_ tableView: UITableView, numberOfRowsInSection section:Int) -> Int {
...
}
and the final code look like
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
tableView.rowHeight = 200;
...
}
this code will increase the table Row cell height to 200 the default height is 44
I too experienced this warning with moving to Xcode 6 GM. I was only getting the warning when I rotated the device back to its original position.
I am using custom UITableViewCells. The storyboard table view is set to my custom size (100.0 in my case). While the table cells render properly as they have in previous releases, I did not like warning message.
In addition to the above ideas, I added this
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 100.0;
}
Screen renders... responds to rotation and no more warning messages.
In xcode 6.0.1 I had removed this warnings specifying the row height using:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44.0;
}
You may also see this message if your only constraints are set to align all items vertically and you don't have/want a height specified for the cell. If you set a top/bottom constraint on the item the warning will disappear.
I had this problem when my labels and views in the custom tableViewCell were constrained to the customCell, not its Content View. When I cleared the constraints and connected them to cells Content View the problem was solved.
I had the same error message,
make sure all your outlets are valid like table view and tableview Constraints
I have also similar issue for custom tableview cell which has dynamic row height. Dynamic height wasn't reflected and got the same warning in console. The solution is Adding subviews to cell instead of contentView. BTW, I have created subviews programatically.
I have this issue on TableViewCells where the constraints are set on initialisation but where the cell's contents are loaded afterwards, this means the autolayout engine can't determine the height. The other solutions here don't work because I need the cell's height to be UITableView.automaticDimension.
I just added an extra constraint to the cell:
contentView.heightAnchor.constraint(equalToConstant: 44, priority: .defaultLow)
In the storyboard set the cell Row height field with the same value as Row height in tableView (both with the same value worked for me).
If you add heightForRowAtIndexPath function to your code it may induce a performance issue because it will be called for each cell so be careful.
If you are making a dynamic height calculation,
you should have all elements linked to each other in terms of constraints like top and bottom.
you should definitely have a bottom constraint that is linked to the element at the bottom of your cell
if you are extending your ViewController class with UITableView and also using navigation controller to show the screen then you dont need to perform segue with identifier this may cause an error of identifier ViewController, you can use pushViewController method to show the chat screen in order to get rid from this error so here is the code just paste it in to your UItableView delegate
let chatBox = ChatBoxViewController()
navigationController?.pushViewController(chatBox, animated: true)
just put the name of your viewcontroller which you want to show next and yeah done.
I have same error, due to this line this error was shown.
self.layer.backgroundColor = UIColor(white: 1, alpha: 0.2) as! CGColor
I just change the line as following to fix the error
self.layer.backgroundColor = UIColor(white: 1, alpha: 0.2).cgColor

Resources