Pan gesture interferes with scroll

泪湿孤枕 提交于 2019-12-03 00:50:31

Alright, here is the short answer:

You have to use UIGestureRecognizer's method -requireGestureRecognizerToFail:.

And here is the long answer:

You have to make the pan gesture recognizer of your scroll view to succeed only if the pan gesture recognizer of TimerViewController fails. However that gesture (TimerViewController's gesture) should only succeed if the initial movement is vertical. If it is horizontal it should fail. To accomplish this we have to subclass UIPanGestureRecognizer and modify it to fit those needs. Here is what you have to do:

  1. Disregard ALL the changes you made from my previous answer
  2. Add VerticalPanGestureRecognizer to your project.
  3. Modify TimerViewController as shown.
  4. Modify ScrollViewController as shown.

VerticalPanGestureRecognizer.h

#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>

@interface VerticalPanGestureRecognizer : UIPanGestureRecognizer

@end

VerticalPanGestureRecognizer.m

#import "VerticalPanGestureRecognizer.h"

@interface VerticalPanGestureRecognizer ()

@property (nonatomic, assign) CGPoint origLoc;

@end

@implementation VerticalPanGestureRecognizer

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    self.origLoc = [[touches anyObject] locationInView:self.view.superview];
    [super touchesBegan:touches withEvent:event];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    if (self.state == UIGestureRecognizerStatePossible) {
        CGPoint loc = [[touches anyObject] locationInView:self.view.superview];
        CGFloat deltaX = fabs(loc.x - self.origLoc.x);
        CGFloat deltaY = fabs(loc.y - self.origLoc.y);
        if (deltaY < deltaX)
            self.state = UIGestureRecognizerStateFailed;
    }

    [super touchesMoved:touches withEvent:event];
}

@end

TimerViewController.h

// Your imports here

@interface TimerViewController : UIViewController

{
    // Your ivars here
}

// Add the following property
@property (nonatomic, strong) UIPanGestureRecognizer *pan;

// Your methods here

@end

TimerViewController.m

#import "TimerViewController.h"
#import "VerticalPanGestureRecognizer.h"

@implementation TimerViewController
@synthesize pan = _pan;

// prefersStatusBarHidden method here

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil // Initialise view controller
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

    if (self) {

        // Instantiate the pan gesture as "VerticalPanGestureRecognizer"
        self.pan = [[VerticalPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; // Create recogniser for a pan guesture
        self.pan.maximumNumberOfTouches = self.pan.minimumNumberOfTouches = 1;
        [self.view addGestureRecognizer:self.pan];
    }

    return self;
}

// The rest of your code here

@end

ScrollViewController.m

- (void)viewDidLoad
{
    // Your code here

    TimerViewController *tvc = [[TimerViewController alloc]init];
    CGRect frame = tvc.view.frame;
    frame.origin.x = 320;
    tvc.view.frame = frame;

    // Add the following line 
    [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:tvc.pan];

    [self addChildViewController:tvc];
    [self.scrollView addSubview:tvc.view];
    [tvc didMoveToParentViewController:self];

    // More code here
}

This new approach works perfectly. I tested it. Let me know if you have more questions.

Cheers!

UPDATE

To answer the question you posted on the comments, here is what you have to do:

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

    BarsViewController *bvc = [[BarsViewController alloc]init];
    [self addChildViewController:bvc];
    [self.scrollView addSubview:bvc.view];
    [bvc didMoveToParentViewController:self];

    TimerViewController *tvc = [[TimerViewController alloc]init];
    CGRect frame = tvc.view.frame;
    frame.origin.x = 320;
    tvc.view.frame = frame;

    [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:tvc.pan];
    [self addChildViewController:tvc];
    [self.scrollView addSubview:tvc.view];
    [tvc didMoveToParentViewController:self];

    StopwatchViewController *svc = [[StopwatchViewController alloc] init];
    frame = svc.view.frame;
    frame.origin.x = 320*2;
    svc.view.frame = frame;

    [self addChildViewController:svc];
    [self.scrollView addSubview:svc.view];
    [svc didMoveToParentViewController:self];

    self.scrollView.contentSize = CGSizeMake(320*3, self.view.frame.size.height);
    self.scrollView.pagingEnabled = YES;

    [self.scrollView setShowsHorizontalScrollIndicator:NO];
}

Again, I tested it and it's working. You just have to add the gesture recognizer for the bars

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!