UITableViewCell Height Calculation and delegation? - objective-c

I know this question had been asked hundreds of times before, but it's never really been solved (Or at least the way I'd like it to be). I have a rather complex UITableViewCell setup. The cell.backgroundView is loaded from a UIView subclass which uses a fair bit of CoreGraphics and CoreText. The code is rife with CTFramesetterSuggestFrameSizeWithConstraints, so I'm relectant to duplicate the class in the heightForRowAtIndexPath method.
I think I can solve this by creating an NSMutableDictionary with the indexPath as the key and the height as the value. But then I'm faced with the problem of heightForRowAtIndexPath being called first. I believe I can solve this problem by guessing the height of the cell and then once the cell's UIView subclass has finished rendering, use delegation to set the cell's height.
But this leaves me with the problem, how the hell do I delegate this? And, how to I prevent scrolling from being extremely choppy? as the cells will be created and resized in a split second.

In the past, I've used a dummy cell. I have a separate method -fillInCell:forRowAtIndexPath: which puts data into the cell. That way I can fill out the dummy cell in -tableView:heightForRowAtIndexPath: and the real cell in -tableView:cellForRowAtIndexPath:.
If this does not work for you then there are other options.
The first thing that comes to mind is create real cells in -tableView:heightForRowAtIndexPath: instead of -tableView:cellForRowAtIndexPath:. You can store completed cells in a mutable dictionary. -tableView:cellForRowAtIndexPath: will simply pull the completed cell from the dictionary. You should also detect when scrolling has stopped so you can empty your dictionary (just because -tableView:heightForRowAtIndexPath: was called doesn't mean -tableView:cellForRowAtIndexPath: will get call for the same indexPath).
Hope that helps.

Related

JSON, cellForRowAtIndexPath bug

Struggling to find where fault is with my code. On first view load, everything works and loads fine as it should, but when i revisit that view, it seems that the first two cells are empty. I logged the dictionary (dict) in viewWillAppear: and it logs the data fine, so error has to be in cellForRow method. Take a look at my method, and see where i'm going wrong, the third cell populate third piece of data, so i'm totally stumped, but the first two cells are completely blank, no data.
http://pastebin.com/Va84MG5g
First of all, why are you doing all of that insane UITableViewCell customization inside of your tableView:cellForRowAtIndexPath: method? Create a custom UITableViewCell subclass and do the set up there.
In the class's initWithStyle: method, add all of your subviews with a frame of CGRectZero, because at initialization, the table view cell doesn't know how big it is. You can set text alignments, colors, etc. here as well. Then, in layoutSubviews, go ahead and set all the frames. Override prepareForReuse and set things like your UIImageViews to nil. This will help with performance for reused cells.
As for why you're not seeing your data in your first two cells, my initial thought is that it has something to do with the way you're setting up your cells for reuse. You're asking your tableView to dequeue a regular UITableViewCell and only creating all of these subviews if the returned cell is nil. So what happens when it returns a UITableViewCell? You skip the part where you alloc/init all these subviews, and so you're basically adding nothing to the cell. I feel if you create a custom subclass and ask your UITableView to dequeue that instead, you'll get the result you're looking for.
NOTE: If you're targeting at least iOS 5, you can create your UITableViewCell's layout in a nib and register the nib with the table view. Doing so will guarantee that you always get a dequeued cell, and you never have to do your if (cell == nil) check. If you're targeting iOS 6, you can register a UITableViewCell subclass.

iOS 6.0 UICollectionView - same cells being added multiple times

While using collection view, in cellforItemAtIndexPath, new cell instance is being added multiple times (on top of another) at same location/frame, even though correct reuseidentifier is being passed to "dequeueReusableCellWithReuseIdentifier:forIndexPath:"
The cell mentioned above is a subclass of UICollectionViewCell and contains UITextField with proper frame. When scrolling and textfield is first responder, the above said problem is occurring.
Please let me know of any pointers to address the issue.
This could be a bug in UICollectionView related to one I've already filed with decoration views. As long as your cells are opaque, it should not affect your interface
It's possible (though, imo, not very likely) that this is correct behaviour for UICollectionView and it uses those extra cells for interface orientation. At any rate, the problem seems much less pronounced that the one with decoration views, which would add dozens of copies of the decoration view. As long as it's not affecting your app, I'd say live with it.

UITableView: how to make it not recycle cell?

Is there a way to make table view not recycle UITableViewCell so after all cells are loaded, it won't ask for cells(ie tableView:cellForRow...)?
I know I can put the table view in a scroll view and make the table view to have the same size as the scroll view, so all cells will be loaded, but some of my cells have variable sizes, then I need to update the scroll view's content size after the cells' sizes are changed.
Is there any other way to do this?
update:
Sorry for the misleading, actually I mean how to make it not REMOVE cells once created, so if there are ten cells, and there won't be any cell returned by dequeueReusableCell and after ten tableView:cellForRow: it won't call it again.
Simply not use reusable identifier will make it create new cell every time as needed, even the cell at position 1 has been created but then reused for position 2.
Set the reuseIdentifier to nil.
This is much better than using a different identifier for each cell, as the table can now dispose unneeded cells quickly. If they have some identifier set, there's no way to tell if you will ever reuse them.
So you don't have to miss the reuse part completely, just for the cells you don't want to. If the new cell contains the same subviews (maybe just layout and configured differently) - it might still be better to reuse.
Just don't use a cellIdentifier, or use a different identifier for each cell.
just dont use - (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
in the cellForRowAtIndexPath method and create a new cell everytime.
Other way is to give a different cell Identifier for each cell you create.
Now, If you can elaborate on why you dont want the tableview to recycle its cells (which is one of the powerful feature of tableview), may be you can find out other ways to achieve the same thing with reusing the cells..!!
Hope it helps..:)

Unload specific UITableViewCells

Is there a way to unload/release a UITableViewCell such that the containing UITableView calls cellForRowAtIndexPath: when it is needed again?
I understand that this is exactly what UITableView does by default, but only once the cells are outside the tableview frame. My custom view uses UITableView in such a way that its frame == content size.
If there is no way to unload specific cells, I'll have to think of a different approach.
The method [UITableView reloadRowsAtIndexPaths:withRowAnimation:] allows you to tell the table view to reload one or more cells. This will reload the specified cell(s) if they are on screen and presumably do nothing if they aren't currently on screen. Sounds like what you want though your question is not entirely clear to me.

Changing UITableCellView appearance before it is highlighted (from UITableView)

I may have taken a million wrong turns to get to this question, so I'm happy to revise if someone can spot where I went wrong.
I am trying to build a tableview that looks the same as the Contacts app. My first issue is that an entry will have both a bolded and unbolded string in a given row like "John Appleseed" or "Martin Luther King". I figured I need have two UILabels within my UITableViewCell (possible my first mistake).
All I want to do is simply add that second UILabel so instead of subclassing I just add another UILabel in UITableViewCell (possible my next mistake).
However when a row is highlighted (but not yet selected) the default UILabel text switches to white, but my ad-hoc UILabel remains black. I can only force the UILabel text to change to white in the UITableViewDelegate methods which occur AFTER the highlighting. This cause I noticeable flash of white -> black.
Now I see the UITableViewCell method 'setHighlighted:animated:' which I could override if I subclassed, but I was hoping the were another way to approach it.
Thoughts?
I think you're going to find it difficult to keep the last name proportionally spaced from the other portion of the name in a separate view, especially given that the views may be resized by the table view in a number of situations (for example, to accommodate controls when the table view is in editing mode).
It should be a lot easier to create a custom subclass of UITableViewCell and override its -drawRect: method to draw the text itself. Take a look at the UIStringDrawing category on NSString for a list of messages you can send to an instance of NSString to tell it to draw itself either at a given point, or within a given rectangle.