I'm having a problem that seems like it shouldn't really be a problem. I'm trying to create a comments ("chat") view for my app, but I'm using estimated row heights and can't find a nice way to have the comments start at the bottom, such that when the view is loaded, the latest comment is at the bottom of the screen, just above the input area also at the bottom of the screen.
I've been looking around for ages and have found solutions like these:
[self.tblComments scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Doesn't work nicely because it uses the estimated row height, which isn't always right (some comments will be much longer).
[self.tblComments setContentInset:UIEdgeInsetsMake(self.tblComments.bounds.size.height - self.tblComments.contentSize.height, 0, 0, 0)];
Same problem as above (contentSize is determined by estimatedRowHeight).
I'm sure there's a perfect solution to this somewhere since so many apps have views like this, I just can't find it. I'd love any insight into something I may be missing here...
Edit:
contentSize
is simply "The size of the content view." But since you've set a value for estimatedRowHeight
, all your off-screen cells are assumed to be of height estimatedRowHeight
.
According to the docs, here's the point of estimatedRowHeight
:
Providing a nonnegative estimate of the height of rows can improve the performance of loading the table view. If the table contains variable height rows, it might be expensive to calculate all their heights when the table loads. Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.
So basically, in order to save time, the table is making an assumption about row height and thus content size based on your estimatedRowHeight
. By using estimatedRowHeight
you're asking your UITableView
to make these "shortcuts" in order to improve performance. You're basically telling the program not to calculate the row heights ahead of time, so in order to get the row heights and content sizes of any off-screen content, you have to calculate them manually. As long as you decide to set an estimatedRowHeight
, this is unavoidable.
My guess is that many chat apps you've looked at don't use estimatedRowHeight
in order to avoid this issue...
But if you do in fact feel as if using estimatedRowHeight
helps with your app's performance, here are two suggestions.
SUGGESTION #1
Perhaps it makes sense to have a totalChatHeight
variable where you keep track of the total row heights as they come in, calculated using similar logic as your heightForRowAtIndexPath:
method. By originally calculating this info in the background as the comments load then incrementing as you go, you'd still maintain the performance benefits of using estimatedRowHeight
without sacrificing the functionality of having the table know its row heights.
By doing this, you can structure your contentOffset
statement like so to scroll to the bottom using the known table row height information:
CGPoint bottomOffset = CGPointMake(0, totalChatHeight - self.tblComments.frame.size.height);
[self.tblComments setContentOffset:bottomOffset animated:YES];
SUGGESTION #2
Another suggestion would be to calculate your row average dynamically so you have a more precise measurement for estimatedRowHeight
and the contentSize
of your UITableView
would approximately be the same with or without using estimatedRowHeight
. That way estimatedRowHeight
is actually the estimate row height and the estimated content size should also be near the actual contentSize
, so this standard contentOffset
formula should work:
CGPoint bottomOffset = CGPointMake(0, self.tblComments.contentSize.height - self.tblComments.frame.size.height);
[self.tblComments setContentOffset:bottomOffset animated:YES];
This could potentially be dangerous though as both the chat log and rounding error grow.
SUGGESTION #3 <-- Perhaps the best way to go in this case
This third suggestion may be the easiest to implement in your case as it doesn't require any ongoing calculations:
Just set estimatedRowHeight
to the last row's height before reloading the table's data.
You can calculate that new row's height using whatever algorithm you use in heightForRowAtIndexPath:
then set estimatedRowHeight
to that height; that way you can use this statement to scroll to the last cell
[self.tblComments scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
and even though, as you said, it determines the row position based on estimatedRowHeight
, it should scroll to the correct position as long as the estimatedRowHeight
equals the bottom row height.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With