UIPinchGestureRecognizer only for pinching out

一个人想着一个人 提交于 2019-12-12 04:37:17

问题


I'm trying to create a UIPinchGestureRecognizer that fails if the user pinches out (moves there fingers apart). I know there is a really easy way to do this by just taking the scale of t he recogniser in the action method and if it is larger than 1, set a flag and ignore all the future calls. However, this does not work for me, I have other gesture recognisers that require this pinch recogniser to fail, so I need it to fail properly when the user pinches in the wrong direction.

I have attempted to subclass UIPinchGestureRecognizer:

@implementation BHDetailPinchGestureRecogniser {
    CGFloat initialDistance;
}

#pragma mark - Object Lifecycle Methods

- (id)initWithTarget:(id)target action:(SEL)action {
    self = [super initWithTarget:target action:action];
    if (self) {
        initialDistance = NSNotFound;
    }
    return self;
}

#pragma mark - UIGestureRecogniser Methods

- (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)recogniser {
    if ([recogniser isKindOfClass:[UIPinchGestureRecognizer class]]) {
        return [self.delegate gestureRecognizerShouldBegin:self];
    } else return false;
}

- (void)reset {
    [super reset];
    initialDistance = NSNotFound;
}

#pragma mark - Touch Handling Methods

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (touches.count >= 2) {
        if (self.state == UIGestureRecognizerStatePossible) {
            // Keep hold of the distance between the touches
            NSArray *bothTouches = [touches allObjects];
            CGPoint location1 = [(UITouch *)bothTouches[0] locationInView:self.view];
            CGPoint location2 = [(UITouch *)bothTouches[1] locationInView:self.view];
            initialDistance = [self distanceBetweenPoint:location1 andPoint:location2];
        }
    } else {
        // Fail if there is only one touch
        self.state = UIGestureRecognizerStateFailed;
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Moved. (tc, %lu) (state, %i) (id, %f)", (unsigned long)touches.count, self.state, initialDistance);
    if (touches.count >= 2) {
        if (self.state == UIGestureRecognizerStatePossible) {
            if (initialDistance != NSNotFound) {
                // Get the new distance and see if is is larger or smaller than the original
                NSArray *bothTouches = [touches allObjects];
                CGPoint location1 = [(UITouch *)bothTouches[0] locationInView:self.view];
                CGPoint location2 = [(UITouch *)bothTouches[1] locationInView:self.view];
                NSLog(@"Checking distance between points.");
                if ([self distanceBetweenPoint:location1 andPoint:location2] < initialDistance - 3.f) {
                    NSLog(@"Began");
                    self.state = UIGestureRecognizerStateBegan;
                } else if ([self distanceBetweenPoint:location1 andPoint:location2] > initialDistance) {
                    NSLog(@"Failed");
                    self.state = UIGestureRecognizerStateFailed;
                }
            }
        } else {
            self.state = UIGestureRecognizerStateChanged;
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.state == UIGestureRecognizerStatePossible) self.state = UIGestureRecognizerStateFailed;
    else [super touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    self.state = UIGestureRecognizerStateCancelled;
}

#pragma mark - Helper Methods

- (CGFloat)distanceBetweenPoint:(CGPoint)point1 andPoint:(CGPoint)point2 {
    return sqrtf(powf(point1.x - point2.x, 2) + powf(point1.y - point2.y, 2));
}

@end

What I have realised that it is not that simple, it will need to handle multiple touches, sometimes touches moved only has one touch so it will need to keep hold of the touches, one touch might end and another start and this still want to be part of the pinch. It seems like I am loosing the build in functionality of the pinch recogniser when all I want to do is make it fail if the user pinches in the wrong direction.

Is there a simpler way to achieve this behaviour without completely rewriting UIPinchGestureRecognizer? It is probably worth mentioning that I have no control over the other recognisers that I want to fail (they are deep in the bowls of a PSPDFViewController (third party library)).


回答1:


How about using the gesture recogniser's delegate to help?

Set a delegate with the following implementation of gestureRecognizerShouldBegin

func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
    if let pinch = gestureRecognizer as? UIPinchGestureRecognizer {
        return pinch.scale < 1
    }
    return true
}


来源:https://stackoverflow.com/questions/26781373/uipinchgesturerecognizer-only-for-pinching-out

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