如何在scrollToRowAtIndexPath完成animation时得到通知
这是如何在tableViewController完成animation推送到导航堆栈时得到通知的后续操作。
在tableView
我想取消select一个包含animation的行,但只有在tableView 完成将滚动animation到所选行之后。 如何在发生这种情况时得到通知,或者在结束的时候调用什么方法。
这是事物的顺序:
- 推视图控制器
- 在
viewWillAppear
我select一个特定的行。 - 在
viewDidAppear
我scrollToRowAtIndexPath
(到选定的行)。 - 然后,当滚动完成后,我想
deselectRowAtIndexPath: animated:YES
这样,用户就会知道他们为什么在那里滚动,但是我可以淡出select。
第四步是我还没有弄清楚的部分。 如果我在viewDidAppear
调用它,那么在tableView滚动到那里时,行已经被取消select了,这是不好的。
您可以使用表视图委托的scrollViewDidEndScrollingAnimation:
方法。 这是因为UITableView
是UIScrollView
的子类, 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委托在滚动过程中被更改,但这在大多数情况下都适用,在某些情况下这可能是不希望的。