如何在scrollToRowAtIndexPath完成animation时得到通知

这是如何在tableViewController完成animation推送到导航堆栈时得到通知的后续操作。

tableView我想取消select一个包含animation的行,但只有在tableView 完成将滚动animation到所选行​​之后。 如何在发生这种情况时得到通知,或者在结束的时候调用什么方法。

这是事物的顺序:

  1. 推视图控制器
  2. viewWillAppear我select一个特定的行。
  3. viewDidAppearscrollToRowAtIndexPath (到选定的行)。
  4. 然后,当滚动完成后,我想deselectRowAtIndexPath: animated:YES

这样,用户就会知道他们为什么在那里滚动,但是我可以淡出select。
第四步是我还没有弄清楚的部分。 如果我在viewDidAppear调用它,那么在tableView滚动到那里时,行已经被取消select了,这是不好的。

您可以使用表视图委托的scrollViewDidEndScrollingAnimation:方法。 这是因为UITableViewUIScrollView的子类, UITableViewDelegate符合UIScrollViewDelegate 。 换句话说,表视图是滚动视图,表视图委托也是滚动视图委托。

因此,在表视图委托中创build一个scrollViewDidEndScrollingAnimation:方法,并取消select该方法中的单元格。 有关scrollViewDidEndScrollingAnimation:方法的信息,请参阅UIScrollViewDelegate的参考文档。

尝试这个

 [UIView animateWithDuration:0.3 animations:^{ [yourTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO]; } completion:^(BOOL finished){ //do something }]; 

不要忘记将animation设置为NO,scrollToRow的animation将被UIView animateWithDuration覆盖。

希望这个帮助!

为了解释本·帕卡德对公认答案的评论,你可以这样做。 testingtableView是否可以滚动到新的位置。 如果不是,立即执行你的方法。 如果可以滚动,请等到滚动完成后执行您的方法。

 - (void)someMethod { CGFloat originalOffset = self.tableView.contentOffset.y; [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionMiddle animated:NO]; CGFloat offset = self.tableView.contentOffset.y; if (originalOffset == offset) { // scroll animation not required because it's already scrolled exactly there [self doThingAfterAnimation]; } else { // We know it will scroll to a new position // Return to originalOffset. animated:NO is important [self.tableView setContentOffset:CGPointMake(0, originalOffset) animated:NO]; // Do the scroll with animation so `scrollViewDidEndScrollingAnimation:` will execute [self.tableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; } } - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { [self doThingAfterAnimation]; } 

您可以在[UIView animateWithDuration:...]块中包含scrollToRowAtIndexPath:在所有包含的animation结束后触发完成块。 所以,这样的事情:

 __weak MYViewController *me = self; [UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionAllowUserInteraction animations:^ { // Scroll to row with animation [me.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; } completion:^(BOOL finished) { // Deselect row [me.tableView deselectRowAtIndexPath:indexPath animated:YES]; }]; 

以Swift扩展实现这个。

 //strong ref required private var lastDelegate : UITableViewScrollCompletionDelegate! = nil private class UITableViewScrollCompletionDelegate : NSObject, UITableViewDelegate { let completion: () -> () let oldDelegate : UITableViewDelegate? let targetOffset: CGPoint @objc private func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) { scrollView.delegate = oldDelegate completion() lastDelegate = nil } init(completion: () -> (), oldDelegate: UITableViewDelegate?, targetOffset: CGPoint) { self.completion = completion self.oldDelegate = oldDelegate self.targetOffset = targetOffset super.init() lastDelegate = self } } extension UITableView { func scrollToRowAtIndexPath(indexPath: NSIndexPath, atScrollPosition scrollPosition: UITableViewScrollPosition, animated: Bool, completion: () -> ()) { assert(lastDelegate == nil, "You're already scrolling. Wait for the last completion before doing another one.") let originalOffset = self.contentOffset self.scrollToRowAtIndexPath(indexPath, atScrollPosition: scrollPosition, animated: false) if originalOffset.y == self.contentOffset.y { //already at the right position completion() return } else { let targetOffset = self.contentOffset self.setContentOffset(originalOffset, animated: false) self.delegate = UITableViewScrollCompletionDelegate(completion: completion, oldDelegate: self.delegate, targetOffset:targetOffset) self.scrollToRowAtIndexPath(indexPath, atScrollPosition: scrollPosition, animated: true) } } } 

尽pipeTableView委托在滚动过程中被更改,但这在大多数情况下都适用,在某些情况下这可能是不希望的。