iOS Pinch Scale и Two Finger Rotate одновременно - PullRequest
26 голосов
/ 13 ноября 2011

Вот мой код:

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;
    }
}

Мое вращение прекрасно работает само по себе, и мой масштабпрекрасно работает сам по себе, но они не будут работать вместе.Один всегда работает, а другой нет.Когда я внедряю shouldRecognizeSimrallelouslyWithGestureRecognizer, кажется, что два жеста борются друг с другом и дают плохие результаты.Что мне не хватает?(Да, я реализовал <UIGestureRecognizerDelegate>)

Ответы [ 3 ]

34 голосов
/ 13 ноября 2011

Каждый раз, когда вызывается 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 намного сложнее.

8 голосов
/ 13 ноября 2011

Чтобы это произошло, вам нужно реализовать делегат жестов 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;
}

Этот код необходимо изменить для представления, для которого вы хотите одновременноераспознаватель жестов.Код выше - то, что вам нужно.

7 голосов
/ 14 апреля 2017

Swift 3 с панорамированием, поворотом и зажимом

// 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
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...