2012-03-26 69 views
2

我有一个项目,我需要在iPad上的相同视图内显示多个UITableView实例。他们也恰好轮流,但我相当肯定这是无关紧要的。用户应该不知道该视图是由多个表视图组成的。因此,我想这样做是为了当我滚动一个tableview时,其他人同时滚动它。同步多个UITableView实例的滚动位置

由于UITableViewUIScrollView的子类,我想我可以处理UIScrollViewDelegate方法并将它们传递给所有的tableviews。不幸的是,虽然我可以捕获一些事件,但方法调用粒度不够好,我无法将这些消息传递给其他的tableviews。我能得到的最接近的是执行-scrollViewDidScroll:,然后在每个tableview上调用-setContentOffset:animated。如果我试图发送这个消息来处理所有潜在的情况,我最终会锁定,因为-scrollViewDidScroll正在为我的-setContentOffset:animated调用呼叫,所以我最终冻结了。无论如何,如果我通过仅使用此方法来检测一个tableview上的滚动并将其传递给其他tableview,我发现尽管其他tableviews最终会滚动到同一位置,但它们落后于第二个或二。

Here's a sample project I created.

我如何能实现没有子UITableView这种行为?

回答

10

您可以通过直接观察contentOffset来避开回调粒度问题。在viewDidLoad,成立国际志愿者组织在每个需要同步的表视图:

for(UITableView *view in self.tableViewCollection) 
{ 
    [view addObserver:self 
      forKeyPath:@"contentOffset" 
       options:NSKeyValueObservingOptionNew 
       context:NULL]; 
} 

然后,当你观察到的变化,暂时脱钩的观察,更新其他表视图偏移,并把观察回。

- (void)observeValueForKeyPath:(NSString *)keyPath 
         ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context 
{ 
    static BOOL isObservingContentOffsetChange = NO; 
    if([object isKindOfClass:[UITableView class]] 
     && [keyPath isEqualToString:@"contentOffset"]) 
    { 
     if(isObservingContentOffsetChange) return; 

     isObservingContentOffsetChange = YES; 
     for(UITableView *view in self.tableViewCollection) 
     { 
      if(view != object) 
      { 
       CGPoint offset = 
       [[change valueForKey:NSKeyValueChangeNewKey] CGPointValue]; 
       view.contentOffset = offset; 
      } 
     } 
     isObservingContentOffsetChange = NO; 
     return; 
    } 

    [super observeValueForKeyPath:keyPath 
         ofObject:object 
          change:change 
          context:context]; 
} 

这可能会变得更漂亮,但它可以让人想到。

+0

呜呼!它完美的作品。我完全忘记了关键值观察。谢谢。 – 2012-03-26 20:51:07

+0

难道你不能用一个单独的“ScrollMultiplexer”对象来做到这一点,所以你没有讨厌的n^2观察?一个对象可以观察到所有的UITableView,并且该对象可以将更新发送给所有其他UITableView。这样,就没有循环,也不需要不断地解开。 – StCredZero 2012-10-09 19:06:19

+0

好吧,这已经发生在一个“单独的”对象(视图控制器)上,所以对于我来说这并不明显,但我可以承认这种可能性。 – warrenm 2012-10-09 22:35:48

6

直接使用contentOffset属性而不是setContentOffset:animated来避免滞后。在你的例子中,将第73和74行更改为

self.tableViewMiddle.contentOffset = scrollView.contentOffset; 
self.tableViewBottom.contentOffset = scrollView.contentOffset; 
1

老问题,但这里有一个更简单的方法。

  1. 马克自己作为的UITableViewDelegate:

    class MultiTableViewController: UIViewController, UITableViewDelegate { ... } 
    
  2. 为自己设定不如授人以表观点:

    override func viewDidLoad() { 
        super.viewDidLoad() 
    
        leftTableView.delegate = self 
        rightTableView.delegate = self 
    } 
    

    (你也可以做在Interface Builder这个步骤)。

  3. 实现此方法:

    func scrollViewDidScroll(scrollView: UIScrollView) { 
        leftTableView.contentOffset = scrollView.contentOffset 
        rightTableView.contentOffset = scrollView.contentOffset 
    } 
    

完成。

表视图具有滚动视图,并且UITableViewDelegate协议包含所有UIScrollViewDelegate方法,因此您可以使用它们。