I'm using Autolayout on iOS 8 and make use of UITableViewRowAnimationAutomatic and all of its magic.
When the Tableview appears the cells have a wrong height and the subviews are distributed over the whole cell with a lot of horizontal space between them. When I scroll down or rotate the device and back alls cells are drawn correctly with the correct size.
Debugger says no error and Autolayout warnings are not present.
These cells are only drawn on iPad and I have specified only for sizeclass (Regular | Regular).
Do you any hints what could be the problem?
There are three things that you need to make sure you are doing...
The AutoLayout Constraints should cover the entire height of the cell. So just by looking at the constraints you should be able to say exactly how tall the cell is.
Implement the estimated height for row method...
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return an actual number here. This is a guess of how tall the cells are
return 100;
}
or
// Thanks #rdelmar :-)
self.tableView.estimatedRowHeight = 100;
Implements height for row...
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// return auto dimension here
return UITableViewAutomaticDimension;
}
Once you have done all three of these it will work.
See my blog here for more data (note, there has been an update since I wrote the blog which I haven't updated yet).
http://www.oliverfoggin.com/using-a-static-uitableview-as-a-layout-device/
Related
I have UITableView that contains 4 different types of customized cells in storyboard. Each cell has customized UILabels which get variable amount of text data from backend. I am struggling with making the cells resizing correctly. I would really want to change the height of each cell but I can not use heightForRowAtIndexPath because it is called before cellForRowAtIndexPath, but the height is actually calculated within each customized cell.
I tried writing in each cells' height into an array while the UITableView is loading, then just reloading it all over again once, but no effect. I tried using CGFloat rowHeight = UITableViewAutomaticDimension with no success either. The customized labels in each cell definitely grow with text which I see when I just statically change row height to higher numbers. So, I would need somehow my labels to push on rows to make them grow, not sure.
Different similar posts on stackoverflow that I found did not help.
The issue was that I needed to set up top and bottom constraints to the ContentView and NOT to the cell itself in the storyboard.
Label -> ContentView top and bottom constraints need to be set up. And then UITableViewAutomaticDimension specified in viewDidLoad:
self.tableView.rowHeight = UITableViewAutomaticDimension;
estimatedRowHeight should be set too. For example:
self.tableView.estimatedRowHeight = 76.0f;
First Method called is:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
Second:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Then:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
set a break point in the above methods and test it. So if you want to preset the height use estimatedHeightForRowAtIndexPathmethod.
I have a table view which contains a placeholders while it loads in images. When the image is loaded, I call reloadRowsAtIndexPaths:withRowAnimation:. At this point, the cell changes height, based on the size of the image. When that happens, I want the table view's content offset to remain in place, and for the cells below to be pushed further down, as you might imagine.
The effect I'm getting instead is that the scroll view scrolls back to the top. I'm not sure why this is, and I can't seem to prevent it. Putting beginUpdates() before and endUpdates()after the reloadRows line has no effect.
I am using estimatedRowHeight, as is needed as my table view can potentially have hundreds of rows of different heights. I am also implementing tableView:heightForRowAtIndexPath:.
EDIT: I've set up a demo project to test this, and admittedly I can't get the demo project to reproduce this effect. I'll keep working at it.
It's an issue with the estimatedRowHeight.
The more the estimatedRowHeight differs from the actual height, the more the table may jump when it is reloaded, especially the further down it has been scrolled. This is because the table's estimated size radically differs from its actual size, forcing the table to adjust its content size and offset.
The easiest workaround is to use a really accurate estimate. If the height per row varies greatly, determine the median height for a row, and use that as the estimate.
Always update the UI on the main thread. So just place
[self.tableView reloadData];
inside a main thread:
dispatch_async(dispatch_get_main_queue(), ^{
//UI Updating code here.
[self.tableView reloadData];
});
I had the same problem and decide it by this way: save heights of cells when they loads and give exact value in tableView:estimatedHeightForRowAtIndexPath:
// declare cellHeightsDictionary
NSMutableDictionary *cellHeightsDictionary;
// save height
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cellHeightsDictionary setObject:#(cell.frame.size.height) forKey:indexPath];
}
// give exact height value
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSNumber *height = [cellHeightsDictionary objectForKey:indexPath];
if (height) return height.doubleValue;
return UITableViewAutomaticDimension;
}
I was seeing this, and the fix that worked for me was to choose an estimated row height that is the smallest of the possible rows. It had originally been set to the largest possible row height when the unintended scrolling was happening. I am just using the single tableView.estimatedRowHeight property, not the delegate method.
There's more content in my Table View, but this cell is getting cut off and not showing more content:
... So I'm not able to scroll any more, even there is more content.
If I pull up with my finger it shows more content, but then when I let my finger off the cell it goes back to the state show in the image above.
I've tried making sure I set height and width in the Labels and Images in AutoLayout since I thought that might be a problem, but still hasn't fixed it.
Any ideas? Thanks!
UPDATE - Table View structure in Storyboard
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
id model = self.model[indexPath.row];
if ([model isKindOfClass:[DBase self]]) {
return 520;
}
else {
return tableView.rowHeight; // return the default height
}
}
I was having this problem as well but mine was only cutting off a single cell. I solved it and thought I'd post this here as it may help others in the future
I was using custom cells created from nibs. Some of my cells could change heights so I was also using this:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 61
I figured out the issue was that I was setting top, left, right and height constraints on my view. I needed to set the bottom constraint as well or else my row height would be way smaller than it should be.
So if you are having this problem check if your row heights aren't smaller than the views that they contain.
I suggest adding height and width constraints to your UITableViewContoller or UITableView in the storyboard.main.
Depending on the size of your device, the UITableView size will remain constant unless you set constraints that will work across all devices.
I'm using Apple's DateCell sample Xcode project to figure out how to use a UIPickerView inside of a UITableViewCell, but I'm having some trouble figuring out the constraints that the sample code has set up for the UIDatePicker in the storyboard.
Link: https://developer.apple.com/library/ios/samplecode/DateCell/Introduction/Intro.html
It says that the UIDatePicker has a constraint relative to the actual UITableViewCell, but when I try to set up a constraint between the two, I can't. Ctrl-dragging from the picker to the cell doesn't highlight the cell. I tried doing it with the cell's content view rather than the cell itself, but that doesn't quite produce the same result as in the sample code's storyboard.
These are the constraints set up by the project for the date picker:
And for the cell:
What the sample's storyboard looks like:
How can I reproduce the above image using constraints?
Any help would be greatly appreciated.
I found that the sample's static height was not what I wanted to use anyway, since I have some cells with lots of text that need to have variable heights for each cell. So instead of the approach in the sample which grabs the height of the picker cell from the pre-defined storyboard size, I used UITableViewAutomaticDimension to automatically fit all of my cells for height. If you don't want auto height, it's still pretty easy to adapt the following solution to set the height to a static value, as I mention in step 3.
Set tableview row height to auto when the view loads:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.tableView.estimatedRowHeight = 60.0; // Set your average height here.
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
Add an estimated height so that it works properly (at least in iOS 8). If you don't add this, you might get some buggy behavior when it draws the cell heights.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
For auto height, remember to remove the tableView:heightForRowAtIndexPath: definition if you have one, as it could interfere with the auto settings.
// Don't define this at all if you want the picker cell to have auto height.
//- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
//{ }
If you want to use a static height for the picker cell, then define the tableView:heightForRowAtIndexPath: function and just return the static value here instead of using the auto dimension like the sample does it. Example would be something like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// This would return the static height for the picker, but auto heights for the rest of the cells.
return ([self indexPathHasPicker:indexPath] ? self.pickerCellRowHeight : UITableViewCellAutoDimension);
}
And then you'd modify the sample to set your static height instead of grabbing it from the frame value in viewDidLoad.
// obtain the picker view cell's height, works because the cell was pre-defined in our storyboard
//UITableViewCell *pickerViewCellToCheck = [self.tableView dequeueReusableCellWithIdentifier:kDatePickerID];
self.pickerCellRowHeight = 216;//CGRectGetHeight(pickerViewCellToCheck.frame);
Rather than trying to recreate the same constraints from the sample, I told storyboard to Reset to Suggested Constraints for the UIPickerView, and then added one more. It added the first two in the picture, and then I just added one more for aligning the center X. My view happened to have the shown numbers from the auto settings but yours may be different.
In case you haven't already done it, part of making the picker work is to make sure the dataSource and delegate for the UIPickerView are set to the view controller using storyboard and control clicking and dragging.
I want my UITableView to always show 4 rows, whether it's on retina 3.5 or 4 - with appropriate re-sizing of fonts and subviews in the cell. The app will always be in portrait orientation.
Is there an "elegant" way to do this in storyboard or through constraints?
Or is the best way to determine all the sizes manually, then alter them programmatically?
Set Auto-resize property of UITableView with flexible height, so that it could change height on devices having different screen sizes. Use heightForRowAtIndexPath like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return self.yourTableView.frame.size.height/4;
}
Now, whatever the height of tableview is, you will get same cell heights for all 4 cells.
Note: For your UITableViewCells set view and elements resize properties like flexible height and flexible positions, so that cells' elements get adjusted according to height changes.
I dont understand your question, but if you want to specify the cell height, you can use a UITableViewDelegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath