UITableViewCell of mixed xibs and programmatically generated UITableViewCells - ios

I have to integrate a UITableViewCell generated programmatically from code like so:
UITableViewCell *newCell = [[UITableViewCell alloc] initWithFrame: CGRectMake(0,0, screenWidth, 150];
However the rest of the cells in this table view are generated with xibs that rely on autolayout, and so the original programmer only used the estimatedHeightForRow method rather than the heightForRow.
My programmatically generated table view cell is all botched (has the default estimated height of 64 rather than the frame's height of 150) unless I implement heightForRow whereas the existing cells are botched as soon as I do implement heightForRow in addition to estimatedHeightForRow. Is there a way around this conundrum?
Thanks for any advice.

Firstly, you should use UITableViewCell's designated initializer - initWithStyle:reuseIdentifier: instead the UIView's initWithFrame:. However, I don't think that is the cause of your problem as I have tested initWithFrame: and it appears to default to default style and no reuse identifier.
You haven't said what you are doing with the cell once you instantiate it. Are you using the default layout or adding your own custom views? The default layout (with just a line of text) appears to work correctly in my testing, with the cells being sized according to the amount of text in the textLabel.
If you are adding custom views you need to ensure that the contentView has vertical constraints that fully define its height. For example, if you have two UILabels vertically aligned then you will need a vertical constraints such as #"V:|-10-[label1][label2]-10-|". If the constraints are not fully defined then contentView will collapse to zero and your views will appear overlapping the next cell.
To give a little more detail, when using self-sizing cells UITableView does not look at the frame of the returned cell but rather calls the cell's systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority:. This results in the Auto Layout engine analyzing the cell's constraints to calculate the appropriate layout size. UITableView then sets the cell's frame according to that size and its position in the table.

I would put an if statement in your height for row method and set the heights to their corresponding cell. It would also be easier if I could see code.

Related

What actually defines the height of a UITableViewCell?

I'm working on an iOS App right now and I want to build a view controller that uses a UITableView to create new events in a calendar (very similarly to how iOS handles event creation in the system calendar, actually). The table view has two sections, the first section holding a date picker and the second section holding two custom cells for entering an event name and notes via a text field and a text view. After playing around with them I managed to force-set them to the right size, but in the process I realized that I don't actually understand how iOS calculates individual cell heights, especially in a table view with multiple sections and multiple custom cell classes. So far, I've found a number of things that seem to play a role:
Contents of a cell, e.g. a text field and its constraints
Hugging priority and compression resistance priority of a cells content
Settings for row height and view height in the size inspector of the cell itself:
Arrangement and Autolayout settings in the size inspector of the cell
Settings for the rowHeight and estimatedRowHeight properties of a UITableViewController
The more I look into it, the more complex and confusing it all gets. Maybe one of you can shed some light on this shady bit of Swift magic?
Basically, the rule is that if the table view's rowHeight is UITableView.automaticDimension, then as long as the estimatedRowHeight isn't 0, you'll get automatic row heights, meaning that the height is determined by the cell's autolayout constraints from the inside out.
The settings can be made in respect to the table view as a whole (in code or in the storyboard) or for a single cell using the height delegate method.
Add your constraints in the cell in right way.
don't use tableview "height for cell" delegate method.
use this in your viewDidLoad
self.tableView.estimatedRowHeight = 44.0
self.tableView.rowHeight = UITableView.automaticDimension
I would say that table view has a bit tricky.
Originally it needed to know size of cell before the cell was created.
The height of cell is defined by UITableViewDelegate optional function tableView(_:heightForRowAt:)
If this function is not defined (or delegate is set to nil) then it will take value of tableView.rowHeight
For performance reasons there was also added tableView(_:estimatedHeightForRowAt:) and tableView.estimatedRowHeight
The idea was not to calculate height of every cell during fast scrolling (such calculation may be costly) and use height that is good enough.
So that are the basics before constraints layout.
Then magic came. You can return UITableView.automaticDimension as height (by delegate method or by setting tableView.rowHeight). It will force tableView to calculate height from cells' constraints (note that constraints must define that height so very likely you want to set content hugging and resistance priority of every label, and you will encounter 'errors' in storyboard/xib).
Since that operation is costly you Apple forces you to specify estimated height by yourself. Also it's important to set that value to something that makes sense, otherwise things like programatically scroll won't work correctly.

Change height of UIView inside of UITableViewCell (Storyboards)

I'm trying to create a master UITableViewCell with storyboards. The idea is that this cell contains all the possible subviews, but not all will be shown depending on the data for each cell.
I calculate the appropriate height for each cell depending on the data using the heightForRowAtIndexPath and this is working fine.
What I'm trying to figure out is how to adjust the height of subviews to zero inside the tableViewCell to effectively hide those elements while still respecting the relative constraints I set up (unlike removing the subviews from the superview which messes up all my constraints).
So basically I can't seem to figure out how to update the height(frame) of a subview (UIView) inside a UITableViewCell using storyboards and autolayout.
Any guidance would be awesome, and please let me know if I'm not using the best paradigm or thought process for the desired effect.
Best,
emjoseph
You'll need to use NSLayoutConstraint's. If your cell subviews do not already have fixed heights, you'll need to add them.
Once you've added those constraints, create references to your header file for those constraints. To do this, double click the height constraint so that it reveals itself in your ViewController structure, then control click and drag into your header file.
When you've decided which view to collapse, access your newly declared NSLayoutConstraint and edit the constant value.
Example:
subviewHeight.constant = 0;

Swift: UITableViewCell size to width of parent UITableView with autolayout enabled

I'm experimenting with autolayout and am running into trouble with UITableViewCell since they're created at runtime. My cells are loaded from a xib from the main ViewController. This xib has View mode set to Aspect Fill.
I've read about different ways to do this online and have yet to get any of them working. What's considered the best way to handle this?
It looks like your constraints aren't set properly, as the cell is shorter than the image's height.
Using AutoLayout and self-sizing cells is the easiest way to handle what you want to do. Once your constraints are setup properly for your custom cell, tableView:cellForRowAtIndexPath: can call dequeueReusableCellWithIdentifier:forIndexPath: and all the subview layout will be handled for you.
See the detailed walkthrough by smileyborg in his answer to Using Auto Layout in UITableView for dynamic cell layouts & variable row heights.
He also provides workarounds for the minor issue with the initial cell width being based on the storyboard cell, instead of the tableView width. I worked around it by setting the cell's initial width to the tableView's width, as Rasputin had suggested.

Managing dynamic height for UITableviewCell using iOS 8

I am trying out autoLayout features for dynamic height for UITableViewCell in iOS 8, I followed this blog http://www.appcoda.com/self-sizing-cells/. So here they mention that from iOS 8 managing dynamic height is hassle free.(In the link they have used swift, but I am using objective C)
Now after doing autolayout from xib, then we need to just write this lines of code in viewDidLoad
- (void)viewDidLoad
{
m_tableView.estimatedRowHeight = 83.0f;
m_tableView.rowHeight = UITableViewAutomaticDimension;
}
This is fine and my tableView height changes dynamically based on the content.
I want to know how to have more control on UITableViewCell height.
1) In my app, I want the cell height to be based on the content(data), but I need to have a default height, which will be applied if the content height is less than default height.
2) I want to know what will be the final height of the cell, before displaying to the user, because I want to add some UI elements below each cell.
So what functions I need to use to fulfil my tasks.
You would need to make sure your Storyboard prototype cell has NSLayoutConstraints from top to bottom. Dynamic cell sizing compresses whatever layout constraints you have in place to their maximum compression given the content set in cellForRowAtIndexPath to calculate the final rendered height of that cell. It is very convenient but it also means you need to be careful about setting your constraints correctly.
If you are adding any subviews programmatically, you need to ensure the same rule of thumb is true- there is a complete, deterministic set of constraints from the top of your cell's contentView to the bottom. Additionally, you will need to set any subviews' added in code translatesAutoResizingMaskIntoConstraints property to NO.

UITableViewCell - How to handle dynamic sized content views from Nibs

When I want to have a custom cell, I generally add a UIView subclass to the cell's content view. For the layout of my subviews I use a nib. Then I wire up the nib to my UIView subclass. My issue is how to dynamically size content. Say my view has a lot UILabels inside it. I use layoutSubviews to position all the subviews - but it is only until that is done that I truly know the height of my cell. So currently in tableView:heightForRowAtIndexPath I setup my subview and call layoutIfNeeded so everything is positioned properly. Now I know the height of my cell and return it in the tableView:heightForRowAtIndexPath method. But now when tableView:cellForRowAtIndexPath is called the cell that I am given has a height of 44.0. When I added my subview to it - my subview is outside of its parent's bounds. Then when the cell is later resized in iOS to the height that I said I needed, my content is thrown off because of my autoresizingMask. Just trying to figure out if this is an issue others deal with or if I'm approaching it completely wrong. It just seems backwards that we ask for the height, then create a cell that is not that height.
Unfortunately, this is how UITableViews work: You need to provide the heights before the UITableViewCells are actually rendered.
And yes, everyone has to deal with it. :)
You could create an NSArray, add all your custom contentViews, set their frame according to the expected contentView bounds and then use this array as data source in tableView:heightForRowAtIndexPath: and tableView:cellForRowAtIndexPath:. While this isn't exactly efficient, it works fine for small data sets.
Also, here's a nice tutorial with this topic:
UITableViewCell Dynamic Height (by Matt Long)
A similar question on SO:
How can I do variable height table cells on the iPhone properly?

Resources