Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does UITableView content size update with row insert/delete animation

I am curious when the UITableView's content size is updated after doing an insert/delete animation call. I figured it would be like most [UIView animation...] blocks in that the frame size/content size would be updated immediately even though the animation hasnt completed, but it does not seem to be that way. Any ideas?

like image 808
SLEW Avatar asked Jul 13 '13 22:07

SLEW


2 Answers

Unfortunately, I haven't been able to find a good way to update the contentSize when adding/deleting rows from a UITableView either, but I did find a way to calculate what it will be if you know the index paths of the cells you are adding/removing.

Using the index path of the modified rows, you can calculate the heights of the respective cells with the tableView:heightForRowAtIndexPath: method and add it to the current content size height of the table view. Here's an example if you're adding just one row:

[self.tableView insertRowsAtIndexPaths:@[indexPathOfNewRow] withRowAnimation:UITableViewRowAnimationAutomatic];
CGFloat newCellHeight = [self tableView:self.tableView heightForRowAtIndexPath:indexPathOfNewRow];
CGFloat newContentSizeHeight = self.tableView.contentSize.height + newCellHeight
like image 75
Daren Avatar answered Sep 23 '22 17:09

Daren


It looks like sizeThatFits() can expose the height of a new contentSize that's pending. You can then assign that pending size to have it resolve early for scroll animations.

With something like this:

extension UIScrollView {

    var pendingContentSize: CGSize {
        var tallSize = contentSize
        tallSize.height = .greatestFiniteMagnitude
        return sizeThatFits(tallSize)
    }

    func scrollToBottom(animated: Bool) {
        contentSize = pendingContentSize
        let contentRect = CGRect(origin: .zero, size: contentSize)
        let (bottomSlice, _) = contentRect.divided(atDistance: 1, from: .maxYEdge)
        guard !bottomSlice.isEmpty else { return }
        scrollRectToVisible(bottomSlice, animated: animated)
    }

}

I'm able to write view controller code like this:

tableView.insertRows(at: [newIndexPath], with: .none)
tableView.scrollToBottom(animated: true)

and have the table scroll all the way to the bottom (using the new content size) instead of it scrolling down to the 2nd-to-last row (using the old content size).

like image 24
otto Avatar answered Sep 19 '22 17:09

otto