iOS: How sync two UIScrollview

2019-05-06 12:27发布

问题:

I have two horizontal UIScrollviews. I want to synchronise their scrolling when user drag fingers in either of them. Here is my code:

self.topScrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
self.topScrollView.delegate = self;
self.topScrollView.bounces = YES;

self.bottomScrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
self.bottomScrollView.delegate = self;
self.bottomScrollView.bounces = YES;
...

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    if (scrollView == self.topScrollView)
    {
        self.bottomScrollView.delegate = nil;
    }
    else
    {
        self.topScrollView.delegate = nil;
    }
    ...
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{   
    ...
    self.topScrollView.delegate = self;
    self.bottomScrollView.delegate = self;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    ...
    self.topScrollView.delegate = self;
    self.bottomScrollView.delegate = self;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    // Sync the two scroll views
    if (scrollView == self.topScrollView)
    {
        [self.bottomScrollView setContentOffset:scrollView.contentOffset animated:NO];
    }
    else
    {
        [self.topScrollView setContentOffset:scrollView.contentOffset animated:NO];
    }
    ...
}

The two scroll views do scroll synchronously, however, the problem is all the bouncing and deceleration are gone. The whole scrolling movement becomes really rigid. If I remove all the syncing code, then each scroll view works just fine individually. So, what is the problem? Or can UIScrollView not be synchronised?

回答1:

You can use topScrollView.panGestureRecognizer and bottomScrollView.panGestureRecognizer to take both gesture recognizers and add them to a common superview enclosing both scroll views. Pan gestures on this superview would then be recognized by both children.

You'll most likely also need to be the delegate of both recognizers and let them be recognized simulaneously:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}


回答2:

I worked out the solution according to jszumski's answer. However, my situation is two vertical UIScrollViews side by side (scrollViewLeft and scrollViewRight). It should work for horizontal UIScrollViews without too much modification.

First, create a custom UIScrollView.

//.h file

@interface CSScrollView : UIScrollView

@end

//.m file

@implementation CSScrollView


-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{

    return YES;

}

@end

Secondly, in your mainview,

- (void)viewDidLoad {

    [super viewDidLoad];


    [self.view addGestureRecognizer:self.scrollViewLeft.panGestureRecognizer];

    [self.view addGestureRecognizer:self.scrollViewRight.panGestureRecognizer];

}

That's everything I need to set up two synchronized scrollviews. The real effect is much better than the regular way of sending/subscribing notifications in scrollview's scrollViewDidScroll and synchronize the contentOffset.