How to make a combined gestures?

折月煮酒 提交于 2019-12-04 18:56:09

Well, conceptually you need to subclass UIGestureRecognizer, do some position tracking, and make use of the fact that after importing UIGestureRecognizerSubclass.h the gestures state property becomes read/write to move all the gears around yourself. As and example, I'll include a basic prototype for a diagonal gesture that I tried to build a long time ago. (It needs a few kinks worked out, but overall, it works.)

.H

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

@interface MMDiagnoalSwipeGestureRecognizer : UIGestureRecognizer
@property (nonatomic, readwrite) BOOL shouldReverseYDelta;
@property (nonatomic, readwrite) CGFloat tolerance;
@property (nonatomic, readonly) CGFloat angleOfSwipe;
@end

.M

#import "MMDiagnoalSwipeGestureRecognizer.h"
@interface MMDiagnoalSwipeGestureRecognizer ()
@property (nonatomic, readwrite) CGPoint startingPoint;
@end

@implementation MMDiagnoalSwipeGestureRecognizer


- (id)initWithTarget:(id)target action:(SEL)action {
    self = [super initWithTarget:target action:action];
    if (self) {
        _shouldReverseYDelta = NO;
        _tolerance = 30.0f;
    }
    return self;
}

- (CGFloat)angleOfGestureFromPoint:(CGPoint)start toEndPoint:(CGPoint)end {
    CGFloat deltaY = (_shouldReverseYDelta) ? end.y - start.y : start.y - end.y;
    CGFloat deltaX = end.x - start.x;

    _angleOfSwipe = atan2f(deltaY, deltaX) * 180.0f / M_PI;

    return _angleOfSwipe;
}

- (CGFloat)diagonalDistanceFromPoint:(CGPoint)start toEndPoint:(CGPoint)end {
    CGFloat deltaX = fabsf(start.x - end.x);
    CGFloat deltaY = fabsf(start.y - end.y);

    CGFloat hypotenuse = powf(deltaX, 2.0f) + powf(deltaY, 2.0f);

    return sqrtf(hypotenuse);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (touches.count > 1) {
        if (self.state == UIGestureRecognizerStatePossible) {
            self.state = UIGestureRecognizerStateFailed;
        }
    }else{
        [touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
            UITouch *touch = (UITouch *)obj;
            _startingPoint = [touch locationInView:self.view];
        }];
    }
}

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

    [touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
        UITouch *touch = (UITouch *)obj;
        CGPoint endPoint = [touch locationInView:self.view];
        CGFloat angle = [self angleOfGestureFromPoint:_startingPoint toEndPoint:endPoint];

        if (self.state == UIGestureRecognizerStatePossible) {
            if ([self angleIsWithinDiagonalTolerance:angle] == YES) {
                if ([self diagonalDistanceFromPoint:_startingPoint toEndPoint:endPoint] >= 20.0f) {
                    self.state = UIGestureRecognizerStateRecognized;
                }
            }else{
                self.state = UIGestureRecognizerStateFailed;
            }
        }
    }];
}

- (BOOL)angleIsWithinDiagonalTolerance:(CGFloat)angle
{
//    NSLog(@"%s",__PRETTY_FUNCTION__);
    NSAssert1(_tolerance < 45.0f, @"DiagonalSwipeGestureRecognizer Error: tolerance property must be set to a value less than 45.0f. Otherwise, the gesture will be detected at any angle. If you don't care and want the swipe to be recognized at any angle, remove the NSAssert call from - %s.", __PRETTY_FUNCTION__);
//    NSAssert(_tolerance < 45.0f, @"DiagonalSwipeGestureRecognizer Error: tolerance property must be set to a value less than 45.0f. Otherwise, the gesture will be detected at any angle. If you don't care and want the swipe to be recognized at any angle, remove the NSAssert call from -[MMDiagnoalGestureRecognizer angleIsWithinDiagonalTolerance:].");

    if (angle >= 45.0f - _tolerance && angle <= 45.0f + _tolerance) {
        return YES;
    }else if (angle <= - (45.0f - _tolerance) && angle >= - (45.0f + _tolerance)) {
        return YES;
    }else if (angle >= 135.0f - _tolerance && angle <= 135.0f + _tolerance) {
        return YES;
    }else if (angle <= - (135.0f - _tolerance) && angle >= - (135.0f + _tolerance)) {
        return YES;
    }else{
        return NO;
    }
}

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

}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [self touchesEnded:touches withEvent:event];
    self.state = UIGestureRecognizerStateChanged;
}

- (void)reset {
    //don't call, will be called automatically.
}



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