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

时间:2012-03-26 20:16:33

标签: objective-c ios uitableview uikit

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

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

Here's a sample project I created.

如果不继承UITableView

,如何实现此行为

3 个答案:

答案 0 :(得分:10)

您可以直接观察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];
}

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

答案 1 :(得分:7)

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

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

答案 2 :(得分:2)

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

  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
    }
    
  4. 完成。

    表视图有一个滚动视图,UITableViewDelegate协议包含所有UIScrollViewDelegate方法,所以你可以使用它们。