0

I would like to execute some code after a built-in animation is completed.

I have a UITableView with a lot of cells/rows. Sometimes, when I do some operations and then I need to scroll to the top of my tableView. For that I use :

tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: true)

But I need to perform some code once the top is reached, such a simple select and deselect of the 1rst row.

I implemented func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) from the UIScrollViewDelegate. It works fine (more or less, sometimes the animation isn't really smooth and we don't see the select/deselect "animation") except when I am already at the top of the tableView, then scrollViewDidEndScrollingAnimation isn't called.

So is there a way to execute some code once scrollToRowAtIndexPath:atScrollPosition:animated has been called?

EDIT:

When I'm talking about doing some operations, I'm talking about moving a row using moveRowAtIndexPath:toIndexPath from UITableView.

So when scrolling is needed it's fine, both animations take about the same amount of time. But when no scroll is needed, then the execution of the code I want to do after the animation, starts at the same time than the animation

Nico
  • 6,269
  • 9
  • 45
  • 85
  • Have you tried putting your post animation code into scrollViewDidEndDragging() and/or scrollViewDidEndDecelerating() ? – Abdullah Apr 04 '15 at 04:19
  • Yes I tried them both and they aren't called in my case as it an animation – Nico Apr 04 '15 at 04:49

1 Answers1

3

You can use this Swift code which I adapted from an old Objective-C answer to scroll the view.

// First, test whether the tableView needs to scroll to the new position
var originalOffset = tableView.contentOffset.y;
tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)

var offset = tableView.contentOffset.y;

if (originalOffset == offset) {
    // No animation is needed since its already there
    doThingAfterAnimation();
} else {
    // We know it will scroll to a new position
    // Return to originalOffset. animated:NO is important
    tableView.setContentOffset(CGPointMake(0, originalOffset), animated: false);
    // Do the scroll with animation so `scrollViewDidEndScrollingAnimation:` will execute
    tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: true)
}

And then of course:

func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
    doThingAfterAnimation();
}
Community
  • 1
  • 1
Andrew
  • 15,357
  • 6
  • 66
  • 101
  • I edited the question to add some more information which makes more sense regarding the title of my question. In this case, the need for scrolling is well detected but when I don't have to scroll, the `doThingAfterAnimation` starts at the same time that the animation moving my row while I'm looking for it to start once the animation is done. – Nico Apr 04 '15 at 05:00
  • 1
    If you are _also_ trying to move cells around at the same time, then you would need to add a completion block for those animations using one of the methods [here](http://stackoverflow.com/questions/3832474/uitableview-row-animation-duration-and-completion-callback), and making sure that both the `scrollViewDidEndScrollingAnimation` func _and_ your completion block for your cell movement animations had been called before continuing on to `doThingAfterAnimation`. I _think_ they are always the same animation duration, so you might not need to coordinate them too much... – Andrew Apr 04 '15 at 05:11