1

Structure: I have one UIPageViewController, currently containing two UIViewController (called e.g. MenuVC and ImageScrollVC). In the second UIViewController (the ImageScrollVC) I have a UIScrollView. This UIScrollView contains multiple images. The user should be able to swipe between the images.

I want:

  • The UIPageViewController should only scroll when the user is using two fingers.
    ** So the user can swipe between the 'MenuVC' and the ImageScrollVC with two fingers, anytime.
  • The UIScrollView should only scroll when the user is using one finger.
    ** With the one finger swipe gesture the user can change the images.

Is this possible?

My assumption is to forward a two finger swipe gesture to the underlying UIPageViewController, but I don't know how to do this.

Update:

My ViewController structure:

RootViewController is implementing the UIPageViewController (exactly like the Apple template). MenuViewControlleris the first ViewController in the PageViewController and ImageScrollViewController the second one with the UIScrollView for the images.

enter image description here

Sebastian
  • 3,379
  • 2
  • 23
  • 39

2 Answers2

0

Your assumption is right on. Normally your UIScrollView in the nested ImageScrollVC will handle both one- and two-finger swipes. You can use a custom subclass of UIScrollView in your ImageScrollVC to ignore two-finger swipes so that they will continue up the chain and be handled by the UIPageViewController. For more details, check out this related question, from which the sample code below is based.

The gist of it is that you'll implement -gestureRecognizerShouldBegin: in your UIScrollView subclass; only return YES if the superclass returns YES, and if the number of touches is 1.

-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)recognizer
{
    return recognizer.numberOfTouches == 1 && [super gestureRecognizerShouldBegin:recognizer];
}
Community
  • 1
  • 1
pix0r
  • 31,139
  • 18
  • 86
  • 102
  • This is not working. UIPageViewController is not scrolling. I've updated my question with a picture of my viewController and view structure. – Sebastian Jan 25 '14 at 14:22
0

I think I solved it. It feels that the solution is not the best or nicest one, but it works.

What I did: I created a new UIPanGestureRecognizer and added it to the imageScrollView. This gestureRecognizer has min. and max. touches to 2. In the action method of this recognizer I enabled and disabled scrolling of the imageScrollView.

Also I created a own subclass of UIScrollView and implemented the gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer to return YES.

In code:

MenuViewController: My first UIViewController in the pageVC. The class is doing nothing (for the purpose of this problem). This is only a placeholder to swipe with two fingers and have something to show.

RootViewController:

self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
//... exactly the same code as in the Apple template

//the UIPageViewController should only use 2 finger:
for (UIView* view in [self.pageViewController.view subviews]) {
    if ([view  isKindOfClass:[UIScrollView class]]) {
        UIScrollView* scrollView = (UIScrollView*)view;
        scrollView.panGestureRecognizer.minimumNumberOfTouches = 2;
        scrollView.panGestureRecognizer.maximumNumberOfTouches = 2;
    }
}

ImageScrollViewController:

//self.scrollView is from type 'CustomScrollView'
-(void)viewDidLoad {
  [super viewDidLoad];
  // autolayout would be nicer, but this was faster and easier for me
  self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * _pageImages.count, self.scrollView.frame.size.height);
  //... a for loop to add all UIImageViews as a subView to self.scrollView

  UIPanGestureRecognizer *twoFingerPan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
  twoFingerPan.minimumNumberOfTouches = 2;
  twoFingerPan.maximumNumberOfTouches = 2;
  [self.scrollView addGestureRecognizer:twoFingerPan];
  twoFingerPan.delegate = (CarScrollView*)self.scrollView;
}

//the inner scrollView for the images should not scroll when two fingers are active
- (void)handlePan:(UIPanGestureRecognizer*)recognizer {
  switch (recognizer.state) {
    case UIGestureRecognizerStateBegan:
    case UIGestureRecognizerStatePossible:
        self.scrollView.scrollEnabled = NO;
        break;

    case UIGestureRecognizerStateCancelled:
    case UIGestureRecognizerStateEnded:
    case UIGestureRecognizerStateFailed:
        self.scrollView.scrollEnabled = YES;

    default:
        break;
  }
}

CustomScrollView: I created a subclass for the UIScrollView with the images.

@interface CarScrollView : UIScrollView <UIGestureRecognizerDelegate>

@implementation CarScrollView

//Method has to return YES so that a two finger pan gesture will be used for the outer scrollView/pageViewController
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
  return YES;
}
Sebastian
  • 3,379
  • 2
  • 23
  • 39