I am a swift/xcode newbie, following a book app that demonstrates TableViews with prototype cells using Auto Layout. The book provides completed sample projects, so I have a project to compare to.
The table view cells use images of different heights. I followed the book exactly, used the same images, etc. But the book project displays TableViewCell rows that dynamically adjust to the height of the images, but my project does not.
// both of the projects contain this line
tableView.estimatedRowHeight = 50
// I added this line to get cell rows to dynamically adjust size
tableView.rowHeight = UITableViewAutomaticDimension
With the magic line of code added, my project works perfectly, just like the book project.
My question is why does the book project display properly without the magic line of UITableViewAutomaticDimension code? Is there an attribute setting somewhere that I might have missed? Is there some other way the table view can know to use automatic dimensions?
I have carefully checked all my constraints (they follow the book), all the attributes and sizes in the inspectors for table views, cells, frames, imageviews, and have scoured the net for possible answers. (Which is how I found out about the automatic dimension code magic.)
Does anyone know where else (other than the magic code line) xcode can be told to use automatic dimensions on cell rows? Any suggestions on where I might look to find out why two apparently identical projects product different cell row height sizing behaviours? Thanks
I have tried playing with my code to see how the tableView's cell auto layouts work. I have had these two delegates in my project to auto resize my tableView cell height,
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44.0;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
And it was working as expected, then i just commented these two delegates and put this line in my viewDidLoad method,
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.tableView.estimatedRowHeight = 50;
}
And still it is working as previously.
So i dig a bit into this and i found out that, many developers have had reported about this similar issue you are facing, self.tableView.rowHeight = UITableViewAutomaticDimension; some time behaves weirdly.
Some times it works by just adding
self.tableView.estimatedRowHeight = 50;
(as mine is now), some times you have to add both
tableView.estimatedRowHeight = 50
tableView.rowHeight = UITableViewAutomaticDimension
And in some cases none of the above work but the two delegates that is estimatedHeightForRowAtIndexPath and heightForRowAtIndexPath.
This is what i know so far about UITableViewAutomaticDimension, if you find some other info, do share.
Thanks!
I redid the whole project over again, and now it works properly without the magic line of code. #techloverr contributed a reference here on stackoverflow that (I think) supports my theory of what is going on.
My answer theory is that the default value for cells is automatic dimensioning. This is supported by the reference above.
I think during the first project attempt, I must have manually bumped or adjusted the size of the prototype table cell while loading in the image view or label placeholders.
My theory is that this tiny change caused xcode to remove the default setting and use the new (fixed) cell row height that I accidentally created. The magic code line in turn overrode the new fixed-size "default" setting.
When I redid the whole project from scratch, I took special care to NOT bump the size of the prototype cell in any way. I used all the same constraints, code, etc. And the project built and displayed properly.
Hopefully someone else can benefit from this experience. The xcode IB is touchy!
Related
Nowadays fortunately it's trivial to have an iOS table where every cell has a dynamic height. So in the cell vertical constraints ..
---- top of content view
- vertical constraint to
-- UILabel, with, .lines set to zero
- vertical constraint to
---- bottom of content view
Assume the UILabel texts vary greatly one word, 20 words, 100 words,
In the table set
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 200 // say
and you're done, these days it works perfectly of course.
However, I had the common situation where you load the table, imagine ten cells.
I populate the UILabel with "Loading..."
Only then - say, a second or two later - do we get the information for the text content. It arrives say a second later and the cell changes the text to "Some long text .. with many lines".
In fact I was surprised to learn it seems UITableView does NOT handle this. The cell in question gets stuck on the original short height.
So, after the larger text is set, I tried all permutations of the usual:
maintext.sizeToFit()
contentView.layoutSubviews()
contentView.layoutIfNeeded()
on the cell, doesn't work.
I tried sending a setNeedsLayout and/or layoutIfNeeded to the table itself, doesn't work.
I thought about .reloadData() on the table itself but - doh - that would again trigger the content being drawn from the server and loaded again, so that's not ideal.
Please note that:
Obviously there are any number of workarounds for the specific example such as not using dynamic data
I am completely aware how to manually animate the height of one cell (like when you "expand" one to show something else when the user taps)
This question is about autolayout and table view - which, thanks Apple, nowadays flawlessly handles completely dynamic cell heights involving UILabels with lines zero.
But what about if the text in such a label changes?
It seems that the table view system does NOT handle this.
Surely there's a way?
When the content of a cell changes the layout (in this case, the height) you must inform the table view that the layout has changed.
This is commonly done with either:
tableView.beginUpdates()
tableView.endUpdates()
or:
tableView.performBatchUpdates(_:completion:)
Why is that not triggered automatically?
I suppose it could be to allow you to do your own animation, or you may want to delay the update, or some other reason that doesn't come to mind at the moment.
Or, it may be due to maintaining backward compatibility?
I don't know. I imagine Apple could tell us...
I have a table view controller with a prototype cell with style "Left Detail."
-In my viewDidLoad() I have self.tableView.estimatedRowHeight = 40 and self.tableView.rowHeight = UITableViewAutomaticDimension like many solutions have said to do. However, when my detail label gets too big (like with the description cell), the cell doesn't grow with the text.
-I tried to reload the data in viewDidAppear(animated:) as well, but that didn't help.
-I don't have anything in my heightForRowAtIndex func right now, but have tried to set that too and it didn't fix my problem.
-I also tried cell.sizeToFit() in my cellForRowAtIndexPath after the cells are populated.
Am I missing something obvious? Or is there something in the "Left Detail" style that is restricting the cell height?
You're not missing anything obvious that I'm aware of, but likely running into an edge case involving the built-in cell style. There are a small number of issues with self-sizing where it mostly works for the built-in styles but can fail for certain cases.
This is a side-effect of how the built-in styles manage their labels and constraints differently from how it would be done for a custom cell style. If you examine the built-in cell's content view in the debugger, its constraints array is empty.
For one edge case, if one of the built-in labels was not needed for a cell, Apple optimizes it by completely removing that view from the cell. When that cell gets reused and the label needs to be added back in, the constraints don't get updated for that initial occurrence. It was possible to work around that particular issue by ensuring that both labels always have text, so the view never was removed.
You definitely should not need to include heightForRowAtIndexPath. You should remove that, then see if you can work around the built-in style issue within cellForRowAtIndexPath. If not, you may have to use a custom cell which mimics the Left Detail style.
Either way, I'd recommend submitting a bug report with a small sample project that illustrates that "Left Detail" issue, as Apple has fixed many of these issues and built-in style self-sizing has been far more usable.
I am making an app where I need to use UITableViews to display content in an organized fashion, but since I updated to iOS 8 and Xcode 6 I have been getting a mystery gray box over almost the entire view. This can be seen in the image below. This does not happen on every UITableView, just some (with no apparent pattern).
In iOS 8, you must specify a height in the UITableView's delegate:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 44.0;
}
In iOS 7 and earlier, a default was accepted. See this link for more information.
This is definitely a bug in XCode6-Beta2. I found a workaround. Select the storyboard, and go to the File Inspector utility. Uncheck the option "Use Auto Layout" then click "Disable Size Classes" in the popup.
Auto Layout seems to be quite broken in beta2. Once you turn off Size Classes, the mysterious "ambiguous scrollable content" warnings will also go away.
I was able to turn Size Classes and Auto Layout back on afterward and the gray rectangle is still gone, but everything is in the wrong place after losing the Size Classes info. It's a mess.
Strangely enough, it has to do with the Table View Separator Style. If you set that to None, the problem will go away. But of course, then you have no separators! If you want to use Single Line separators, you have to manually specify a cell height in -tableView:heightForRowAtIndexPath:.
I have no idea why this is the case, but I am guessing it has something to do with the new self-sizing table rows. Time to do some research :)
In iOS 8 the row height can be set automatically for you.
All you have to do is set a top and bottom constraint to the contentView of the UITableViewCell, like this (notice the constraints):
By doing this, the row height will be automatic and you won't need to set a fixed height.
This fixes the gray background color you have encountered.
Resource: http://www.shinobicontrols.com/blog/posts/2014/07/24/ios8-day-by-day-day-5-auto-sizing-table-view-cells
First app, so every problem is new for me :-) I want to make a tab with instructions for my app. These instructions contain several points, so I wanted to make a static table and in each cell should be a textview containing some explanation text. The length however of this text is variable, since I make my app in two languages so I cannot use a defined height for each row or textview. But I don't want that the user to scroll each textview...they should be rather expanded fully so the only thing a user needs to scroll is the tableview.
I hope I explained it enough clearly...any hint how I could do that? I've tried some stuff in the interface builder, however everything remains quite static...
What you could do is use lazy loading of your cellHeights array as explained in this link
Best practices for drawing dynamic UITableView row height
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cellHeights objectAtIndex:indexPath.row] == nil) {
... calculate height for your textview and store it in the array at the correct index…
}
return [[cellHeights objectAtIndex:indexPath.row] floatValue];
}
or refer this link for another approach How can I do variable height table cells on the iPhone properly?
apple has nice example for mac for the same apple example
If you are not expecting user input, then you should use UILabel to display text instead of UITextView. You can use auto layout features to adjust your UILabel to best fit your content.
You should check this documentation to get yourself familiar with auto layout.
I am having a strange issue that i am unable to solve. In my Storyboard, i have set the height of a custom UITableViewCell to be 100.
But when i run the program, the height is not hundred, its 90 and i don't know why. The issue wasn't there until i updated the project to iOS 7. It might be the AutoLayout but Auto layout was already enabled when my app was running on iOS 6 SDK.
Can anyone point out what could be the problem and how i can fix it? Thanks!
Is this the only cell that is supposed to have a row height of 100? If not, I'd try changing the row height attribute of the table view itself.
If this is the only cell, another thing I'd check is if any of your constraints were changed when the project was updated to iOS 7. If you have any ambiguous or conflicting constraints set, they'll show up if you click the yellow/red indicator to the side of the scene in question.
The last thing to check would be if you're calling
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
anywhere. I doubt that's the problem, but you never know.