iOS: How sync two UIScrollview
Asked Answered
B

3

6

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?

Burgher answered 22/5, 2015 at 13:44 Comment(0)
R
5

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;
}
Rapture answered 22/5, 2015 at 13:51 Comment(2)
I tried adding my controller as the delegate, but the assignment crashed with the following exception: '"UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate"Burgher
I guess I can always subclass scroll view and override the method. Cool I think this should work.Burgher
V
1

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.

Vadavaden answered 13/2, 2017 at 2:12 Comment(0)
P
0

@jszumski answer in Swift

  1. Create a custom subclass of UIScrollView
  2. Conform to UIGestureRecognizer delegate
  3. Override the gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:) GestureRecognizerDelegate method
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
  1. Both collection views need to have the same superview. Add both gesture recognizers to your superview
yourSuperview.addGestureRecognizer(scrollView1.panGestureRecognizer)
yourSuperview.addGestureRecognizer(scrollView1)

Hope this helps!

Peachey answered 1/8, 2019 at 11:47 Comment(1)
Hmm, what if the content size of one of the scroll views was dynamic?Kimberliekimberlin

© 2022 - 2024 — McMap. All rights reserved.