同步多个UITableView实例的滚动位置

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

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

这是我创建的示例项目。

如何在不UITableView情况下实现此行为?

您可以通过直接观察contentOffset来解决回调粒度问题。 在viewDidLoad ,在需要同步的每个表视图上设置KVO:

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

这可能会变得更漂亮,但它可以解决这个问题。

直接使用contentOffset属性而不是setContentOffset:animated来避免延迟。 在您的示例中,将第73行和第74行更改为

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

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

  1. 将自己标记为UITableViewDelegate:

     class MultiTableViewController: UIViewController, UITableViewDelegate { ... } 
  2. 将自己设置为表视图的委托:

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

    (您也可以在界面构建器中执行此步骤)。

  3. 实现此方法:

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

完成。

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