简体   繁体   English

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

[英]Syncing the scroll position of multiple UITableView instances

I have a project in which I need to display multiple UITableView instances inside the same view on the iPad. 我有一个项目,我需要在iPad上的同一视图中显示多个UITableView实例。 They also happen to be rotated, but I'm fairly certain this is irrelevant. 它们也恰好是旋转的,但我相当肯定这是无关紧要的。 The user should be unaware that the view is made up of multiple table views. 用户应该不知道视图由多个表视图组成。 Therefore, I'd like to make it so that when I scroll one tableview, the others scroll with it at the same time. 因此,我想这样做,当我滚动一个tableview时,其他人同时滚动它。

Because UITableView is a subclass of UIScrollView , I figured I could handle UIScrollViewDelegate methods and pass them along to all of the tableviews. 因为UITableViewUIScrollView的子类,所以我想我可以处理UIScrollViewDelegate方法并将它们传递给所有的tableview。 Unfortunately, while I can capture some events, the method call granularity is not fine enough and I'm having trouble passing along these messages to the other tableviews. 不幸的是,虽然我可以捕获一些事件,但是方法调用粒度不够好,而且我在将这些消息传递给其他tableviews时遇到了麻烦。 The closest I can get is implementing -scrollViewDidScroll: and then calling -setContentOffset:animated on every tableview. 我能得到的最接近的是实现-scrollViewDidScroll:然后在每个tableview上调用-scrollViewDidScroll: -setContentOffset:animated If I attempt to send this message for all potential cases, I end up locking up because -scrollViewDidScroll is getting called for my -setContentOffset:animated calls, so I end up freezing up. 如果我尝试为所有可能的情况发送此消息,我最终会锁定,因为-scrollViewDidScroll正在调用我的-scrollViewDidScroll -setContentOffset:animated调用,所以我最终冻结了。 Regardless, if I eliminate the lockup by only using this method to detect scrolling on one tableview and then passing it on to the other tableviews, I find that while the other tableviews do end up scrolling to the same location, They lag behind a second or two. 无论如何,如果我通过仅使用此方法检测一个tableview上的滚动然后将其传递到其他tableviews来消除锁定,我发现虽然其他tableviews最终滚动到同一位置,但它们落后于第二个或二。

Here's a sample project I created. 这是我创建的示例项目。

How can I implement this behavior without subclassing UITableView ? 如何在不UITableView情况下实现此行为?

You can get around the callback granularity issue by observing contentOffset directly. 您可以通过直接观察contentOffset来解决回调粒度问题。 In viewDidLoad , set up KVO on each of the table views you need to synchronize: viewDidLoad ,在需要同步的每个表视图上设置KVO:

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

Then, when you observe changes, temporarily unhook the observation, update the other table views' offsets, and turn observation back on. 然后,当您观察到更改时,暂时取消观察,更新其他表视图的偏移,然后重新开启观察。

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

This can probably be made prettier, but it gets the idea across. 这可能会变得更漂亮,但它可以解决这个问题。

Use the contentOffset property directly instead of setContentOffset:animated to avoid the lag. 直接使用contentOffset属性而不是setContentOffset:animated来避免延迟。 In your example, change lines 73 and 74 to 在您的示例中,将第73行和第74行更改为

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

Old question, but here's an easier way. 老问题,但这是一个更简单的方法。

  1. Mark yourself as UITableViewDelegate: 将自己标记为UITableViewDelegate:

     class MultiTableViewController: UIViewController, UITableViewDelegate { ... } 
  2. Set yourself as delegate to the table views: 将自己设置为表视图的委托:

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

    (you can also do this step in interface builder). (您也可以在界面构建器中执行此步骤)。

  3. Implement this method: 实现此方法:

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

Done. 完成。

A table view has a scroll view, and the UITableViewDelegate protocol contains all the UIScrollViewDelegate methods, so you can just use them. 表视图具有滚动视图,UITableViewDelegate协议包含所有UIScrollViewDelegate方法,因此您可以使用它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM