I have a subclass of a UITableViewCell. Its got some additional items on it for a total of 3 labels and up to 2 buttons. When creating the call in cellForRowAtIndexPath I call a method resizeToFitSubviews that resizes labels, and moves buttons around to the right position, it will remove unused buttons, etc. At this point I know the final height of the cell.
I tried to store the height in a NSMutableArray in the UITableViewController so I could return it in the heightForRowAtIndexPath call but for some reason heightForRowAtIndexPath is called before cellForRowAtIndexPath. And it seams its only called once as far as I can tell.
How do I go about knowing the height, when the cell isn't yet created?
I would love to know a better solution to this, but I think after you calculate the height of the cell in cellForRowAtIndexPath you have to let the table know to reload the data in the cell, so then you get to tell it the correct height in heightForRowAtIndexPath. Of course you should make sure that you don't loop yourself by doing it again when you are in cellForRowAtIndexPath after the reload. Sucky, but works.
Related
I'm struggling with wired kind of problem. I have UITableView with one cell. This cell is only holding containerView with childViewController (second tableView). My problem is that, first tableView(parent) must have UITableViewAutomaticDimension row height but it doesn't work (It dosen't know correct size of that cell with second tableView).
How to get correct size of second tableView) ?
Second tableView (inside Cell) have scrollingEnabled turned off (tableView.scrollEnabled = false), first tableView must have correct size of second tableView in order to provide correct scrolling experience.
Since a UITableView inherits from UIScrollView you can use the contentSize property to get this information. This is how the scrollbar works on the side.
I have done a similar thing before (long ago), so the following is somewhat hazy/ irrelevant/ unessecary. There might be some gotchas with unknown/unrendered cell heights in the embedded tableview. I rememeber having to set the tableview height to a large number (forcing all cells to render) fetching the contentSize then resetting the tableview height to the contentSize.height.
Are you shure you really need second table view? If you have just one cell probably you don't need it. I recommend you to calculate table view height as the summ of it's cells heights. If cells of embedded table view have constant height it could be simple. In other case you also could calculate cells height.
The situation is pretty simple (as pretty common as I thought). I have an UITableView in my application that has lets say 3 rows (all are visible on the screen). Next I tap on one of them and this action changes something in all three cells (e.g. change scale of some UIView that is in this every cell) and everything is ok.
This is ok until I have only visible cells on the screen. I know that cellForRowAtIndexPath works only for visible cells. So how can we change such kind of properties (not data properties) for all the cells?
cellForRowAtIndexPath is where you prepare the cell for display. You should be doing the changes in here.
How are you modifying the view scale inside the cells when the user taps on a cell?
You should be triggering a reloadData() on the tableview which will reload the tableview and trigger the cellForRowAtIndexPath calls. You can also reload specific indexes inside the tableview if needed.
Inside your cellForRowAtIndexPath you should use some logic or state variable to control how you configure your cell. Dont dump all the code inside that function, pass arguments to your cell in a function e.g configureCell(subviewScale: CGFloat) and let the cell configure itself.
Dont forget to reset the scale of the subview in prepareForReuse() on your custom cell so that when the cell is about to be dequeued and reused, it gets its properties reset.
I have a custom table view cell. I have a UIView in the tableview cell that is shown only when the table is expanded. I toggle the height for table view cell each time on tap to show the UIView. I also need to detect clicks on some of the components of UIView.
->tablecell1
-->UIView1 height h1
->tablecell2
-->UIView2 height h2
The cell height of the cell should vary according to the size of UIView. Currently I am calling
tableView:heightForRowAtIndexPath: for varying the height on cell click. However this doesn't work if the UIViews are of variable heights and the bigger view gets clipped.
Is there a better way of solving it?
Ok so real quick tableView:heightForRowAtIndexPath: shall not be called by your controller.
The biggest problem I always run into when dynamically sizing cells is that that heightForRowAtIndexPath is called very early on in the table layout process, so essentially the height of each cell must be know prior to asking the tableview to layout. Anyway I am going to assume that you are using a custom table view cell and have placed a UIView inside there... If you haven't, do.
First: Throw a class function into the CustomTableViewCell called heightNeededForTableViewCellWithView:(UIView *)view and determine the height you would want, handle the condition where view is nil and what the default size shall be.
Second: Call this class function when tableView:heightForRowAtIndexPath: is called and since you own the datasource in your controller you can dynamically return the heightNeededForTableViewCellWithView:viewAtRow based off the view you would want to show for that row!
Third: When a user taps a cell, remember which index they tapped and call [tableView reloadData] which will call tableView:heightForRowAtIndexPath:
I have an odd problem I was hoping someone could perhaps explain. Searching yields nothing in this case.
If heightForRowAtIndexPath specifies a height which is taller than that of the contents drawn as a result of cellForRowAtIndexPath then upon scrolling, once the view refreshes its contents, it won't draw some of the cell contents that I've rendered (each row height is dynamic). However, if I reduce the row height somewhat, everything will be rendered correctly.
Is there some documentation pertaining to this problem? Should heightForRowAtIndexPath always return the precise row height based on contents? For example, I just made the row heights rather large so I could always see the contents, but alas, cellForRowAtIndexPath wouldn't be called as many times as it should, and general rendering problems ensued.
Apologies for the fuzzy description, but perhaps those who have experienced the same problem could offer some insight.
Cheers.
If your cell content contains dynamic content which affects the height, you have to return different height values from heightForRowAtIndexPath.
Tableview calls heightForRowAtIndexPath many times so don't do any calculations inside heightForRowAtIndexPath, instead create an array which holds the calculated height values and simply return the values from the array.
I'm constructing a UITableView with variable height custom table cells, their height determined by the size of a contained multi-line UILabel. I've got the tableView:heightForRowAtIndexPath: delegate method wired up and calculating the final height correctly using sizeWithFont:constrainedToSize:.
I've run across strange issue: by the time the data source method tableView:cellForRowAtIndexPath: is called, the correct per-row height has already been determined as described above, but the frame of the cell does not match that height. Instead, the frame.size.height property of the cell is the default cell height of the table view (86 px, as I've set it in Interface Builder, the correct height when the contained UILabel has just one line of text), instead of being the height that tableView:heightForRowAtIndexPath: determined correct for that index path.
I'm producing the cells in cellForRowAtIndexPath: using dequeuing, that is,
// Using storyboards, this never returns nil, no need to check for it
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"SomeIdentifier"];
NSLog(#"%f", cell.frame.size.height); // 86, not correct if the cell contains a multi-line UILabel
It seems, then, that whatever iOS is doing behind the scenes, the dequeuing is not setting the frame property of the cell to match the calculated height. This in itself is not that surprising, dequeuing concerns itself with cell instances, not their geometry. The cells are rendered correctly, though, so the height property is being set somewhere, but it happens after cellForRowAtIndexPath:.
So: when I initially populate the table view, cell.frame.size.height is 86 for all the cells as they appear for the first time when I scroll the list downwards. Since the correct geometry is set sometime after the first cellForRowAtIndexPath: for each row before it's displayed, when I scroll back up, the height property is correct for each cell that comes back into view after being reused.
After this I can scroll the table view back and forth at will, and the height property remains correct for each cell from that point on.
What's the correct way of getting the correct cell height the first time around, before any dequeue-based reuse happens? I need this to do a bit of re-positioning of the subviews of the table cell. Do I need to manually call heightForRowAtIndexPath: in cellForRowAtIndexPath: and then manually set the frame of the freshly created CustomCell instance to match that height? This seems redundant, and I'd need to create a mechanism to detect when the cell is created for the first time with the wrong frame height vs. when it is dequeued with the correct frame height later to avoid this redundancy.
So, if someone can shed some light into what the logic is behind this, I'd appreciate it.
As suggested by Flexo, answering this myself is apparently better than adding an edit to the question. So, here's the previous edit as an answer:
Nevermind, I should read the docs better. I can get the correct frame in the tableView:willDisplayCell:forRowAtIndexPath: method of UITableViewDelegate, so that is the correct place to do subview customization that relies on the correct frame being set, not cellForRowAtIndexPath:.
Interesting that the docs say this, though:
After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out.
...since the correct frame is already there when this delegate method is called. But anyway, problem solved.
Don't forget that the cell is a UIView, so overriding layoutSubviews is also a valid way to get the correct frame and adjust size/position of subviews. Just don't forget to call [super layoutSubviews].
Easiest way I found was just to call cell.layoutIfNeeded() before you do any setup on the cell. This makes sure all the layout constraints are calculated and the frames are set.