iOS Pinch Scale和Two Finger同时旋转

时间:2011-11-13 00:57:53

标签: iphone ios objective-c ipad cocoa-touch

这是我的代码:

viewDidLoad中:

UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];
[self.canvas addGestureRecognizer:pinch];
pinch.delegate = self;

UIRotationGestureRecognizer *twoFingersRotate = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(pinchRotate:)];
[[self canvas] addGestureRecognizer:twoFingersRotate];

twoFingersRotate.delegate = self;

捏和旋转代码:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

-(void)pinchRotate:(UIRotationGestureRecognizer*)rotate
{
    SMImage *selectedImage = [DataCenter sharedDataCenter].selectedImage;

    switch (rotate.state) 
    {
        case UIGestureRecognizerStateBegan:
        {
            selectedImage.referenceTransform = selectedImage.transform;
            break;
        }
        case UIGestureRecognizerStateChanged:
        {
            selectedImage.transform = CGAffineTransformRotate(selectedImage.referenceTransform, ([rotate rotation] * 55) * M_PI/180);
            break;
        }

        default:
            break;
    }
}

-(void)pinch:(UIPinchGestureRecognizer*)pinch
{
    SMImage *selectedImage = [DataCenter sharedDataCenter].selectedImage;
    [self itemSelected];

    switch (pinch.state) 
    {
        case UIGestureRecognizerStateBegan:
        {
            selectedImage.referenceTransform = selectedImage.transform;
            break;
        }
        case UIGestureRecognizerStateChanged:
        {
            CGAffineTransform transform = CGAffineTransformScale(selectedImage.referenceTransform, pinch.scale, pinch.scale);
            selectedImage.transform = transform;
            break;
        }

        default:
            break;
    }
}

我的轮换效果非常好,我的规模本身很好,但它们不会一起工作。一个人总是工作,另一个人不工作。当我实现shouldRecognizeSimultaneouslyWithGestureRecognizer时,两个手势似乎相互对抗并产生不良结果。我错过了什么? (是的,我已经实施了<UIGestureRecognizerDelegate>

3 个答案:

答案 0 :(得分:34)

每次调用pinch:时,您只需根据捏合识别器的比例计算变换。每次调用pinchRotate:时,您只需根据旋转识别器的旋转计算变换。您永远不会将比例和旋转合并为一个变换。

这是一种方法。给自己一个新的实例变量_activeRecognizers

NSMutableSet *_activeRecognizers;

viewDidLoad中初始化:

_activeRecognizers = [NSMutableSet set];

使用一种方法作为两个识别器的操作:

- (IBAction)handleGesture:(UIGestureRecognizer *)recognizer
{
    SMImage *selectedImage = [DataCenter sharedDataCenter].selectedImage;

    switch (recognizer.state) {
        case UIGestureRecognizerStateBegan:
            if (_activeRecognizers.count == 0)
                selectedImage.referenceTransform = selectedImage.transform;
            [_activeRecognizers addObject:recognizer];
            break;

        case UIGestureRecognizerStateEnded:
            selectedImage.referenceTransform = [self applyRecognizer:recognizer toTransform:selectedImage.referenceTransform];
            [_activeRecognizers removeObject:recognizer];
            break;

        case UIGestureRecognizerStateChanged: {
            CGAffineTransform transform = selectedImage.referenceTransform;
            for (UIGestureRecognizer *recognizer in _activeRecognizers)
                transform = [self applyRecognizer:recognizer toTransform:transform];
            selectedImage.transform = transform;
            break;
        }

        default:
            break;
    }
}

您需要这种辅助方法:

- (CGAffineTransform)applyRecognizer:(UIGestureRecognizer *)recognizer toTransform:(CGAffineTransform)transform
{
    if ([recognizer respondsToSelector:@selector(rotation)])
        return CGAffineTransformRotate(transform, [(UIRotationGestureRecognizer *)recognizer rotation]);
    else if ([recognizer respondsToSelector:@selector(scale)]) {
        CGFloat scale = [(UIPinchGestureRecognizer *)recognizer scale];
        return CGAffineTransformScale(transform, scale, scale);
    }
    else
        return transform;
}

如果你只是允许旋转和缩放,这是有效的。 (我甚至测试过它!)

如果要添加平移,请使用单独的操作方法,然后调整selectedImage.center。尝试使用selectedImage.transform进行旋转和缩放平移要复杂得多。

答案 1 :(得分:8)

为此,您需要实现手势委托shouldRecognizeSimultaneouslyWithGestureRecognizer并放置您想要同时识别的手势。

// ensure that the pinch and rotate gesture recognizers on a particular view can all recognize simultaneously
// prevent other gesture recognizers from recognizing simultaneously
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    // if the gesture recognizers's view isn't one of our views, don't allow simultaneous recognition
    if (gestureRecognizer.view != firstView && gestureRecognizer.view != secondView)
        return NO;

    // if the gesture recognizers are on different views, don't allow simultaneous recognition
    if (gestureRecognizer.view != otherGestureRecognizer.view)
        return NO;

    // if either of the gesture recognizers is the long press, don't allow simultaneous recognition
    if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
        return NO;

    return YES;
}

此代码需要修改为您想要同步手势识别器的视图。上面的代码就是你需要的。

答案 2 :(得分:7)

Swift 3 with Pan,Rotate and Pinch

// MARK: - Gesturies

    func transformUsingRecognizer(_ recognizer: UIGestureRecognizer, transform: CGAffineTransform) -> CGAffineTransform {

        if let rotateRecognizer = recognizer as? UIRotationGestureRecognizer {
            return transform.rotated(by: rotateRecognizer.rotation)
        }

        if let pinchRecognizer = recognizer as? UIPinchGestureRecognizer {
            let scale = pinchRecognizer.scale
            return transform.scaledBy(x: scale, y: scale)
        }

        if let panRecognizer = recognizer as? UIPanGestureRecognizer {
            let deltaX = panRecognizer.translation(in: imageView).x
            let deltaY = panRecognizer.translation(in: imageView).y
            return transform.translatedBy(x: deltaX, y: deltaY)
        }

        return transform
    }

    var initialTransform: CGAffineTransform?

    var gestures = Set<UIGestureRecognizer>(minimumCapacity: 3)

    @IBAction func processTransform(_ sender: Any) {

        let gesture = sender as! UIGestureRecognizer

        switch gesture.state {

        case .began:
            if gestures.count == 0 {
                initialTransform = imageView.transform
            }
            gestures.insert(gesture)

        case .changed:
            if var initial = initialTransform {
                gestures.forEach({ (gesture) in
                    initial = transformUsingRecognizer(gesture, transform: initial)
                })
                imageView.transform = initial
            }

        case .ended:
            gestures.remove(gesture)

        default:
            break
        }
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {

        return true
    }