2010-12-04 73 views
30

這得到通知是後續How to get notified when a tableViewController finishes animating the push onto a nav stack.如何當scrollToRowAtIndexPath完成動畫

tableView我想取消與動畫一排,但只有後的tableView有完成動畫滾動到所選行。如何在發生這種情況時得到通知,或在完成時刻調用什麼方法。

這是事物的秩序:

  1. 推視圖控制器
  2. viewWillAppear我選擇某一行。
  3. viewDidAppearscrollToRowAtIndexPath(到選定的行)。
  4. 然後當完成滾動我想deselectRowAtIndexPath: animated:YES

這樣,用戶就會知道他們爲什麼滾動那裏,但我可以消失的選擇。
第4步是我還沒有弄清楚的部分。如果我在viewDidAppear中調用它,那麼在tableView滾動到那裏時,該行已被取消選擇,這是不好的。

回答

56

您可以使用表格視圖委託的方法scrollViewDidEndScrollingAnimation:方法。這是因爲UITableViewUIScrollViewUITableViewDelegate的子類符合UIScrollViewDelegate。換句話說,表視圖是滾動視圖,而表視圖委託也是滾動視圖委託。

因此,在您的表視圖委託中創建一個scrollViewDidEndScrollingAnimation:方法,並取消選擇該方法中的單元格。有關scrollViewDidEndScrollingAnimation:方法的信息,請參閱UIScrollViewDelegate的參考文檔。

+0

再次感謝您! – Andrew 2010-12-04 23:28:39

+0

不客氣。 – 2010-12-04 23:34:45

+41

如果iOS提供帶有完成塊的版本(比如`UIView animateWithDuration:animations:completion`),那麼通知可以是上下文特定的... – pixelfreak 2011-12-09 22:09:10

11

要解決Ben Packard對接受答案的評論,您可以這樣做。測試tableView是否可以滾動到新的位置。如果沒有,立即執行你的方法。如果它可以滾動,請等到滾動完成後執行您的方法。

- (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]; 
} 
8

可以包括scrollToRowAtIndexPath:[UIView animateWithDuration:...]塊將觸發完成塊畢竟包括動畫的結論。所以,這樣的事情:

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

試試這個

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

不要忘記設置動畫爲NO,scrollToRow的動畫將通過UIView的animateWithDuration覆蓋。

希望得到這個幫助!

0

在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) 
     } 
    } 
} 

雖然滾動,這在某些情況下是不希望在的TableView委託改變這適用於大多數情況下。