2011-11-13 10 views
25

Oto mój kod:iOS Pinch Skala i Two Finger obracają się jednocześnie

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; 

Kod Na Pinches i obraca:

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

Moja rotacja działa świetnie na jego własna i moja skala działa doskonale na własną rękę, ale nie będą działać razem. Zawsze działa, a drugi nie. Kiedy zaimplementujęRemognizeSimultaneouslyWithGestureRecognizer, oba gesty zdają się walczyć ze sobą i przynoszą słabe wyniki. czego mi brakuje? (Tak, zaimplementowałem <UIGestureRecognizerDelegate>)

Odpowiedz

33

Za każdym razem, gdy wywoływana jest nazwa pinch:, obliczasz transformację w oparciu o skalę rozpoznawania szczypców. Za każdym razem, gdy wywoływana jest nazwa pinchRotate:, obliczasz transformację na podstawie obrotu rotora. Nigdy nie łączysz skali i rotacji w jedną transformację.

Oto podejście. Daj sobie jedną nową instancję zmiennej, _activeRecognizers:

NSMutableSet *_activeRecognizers; 

zainicjować w viewDidLoad:

_activeRecognizers = [NSMutableSet set]; 

Wykorzystanie jednej metody jako skargi o oba aparatów rozpoznawania:

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

Będziesz potrzebujesz tej metody pomocniczej:

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

Działa to, jeśli po prostu pozwalasz na obracanie i skalowanie. (Przetestowałem to nawet!)

Jeśli chcesz dodać panoramowanie, użyj oddzielnej metody działania i po prostu dostosuj selectedImage.center. Próba robienia panoramy z rotacją i skalowaniem przy użyciu selectedImage.transform jest znacznie bardziej skomplikowana.

+0

Czy możesz dać mi przykład kodu, w jaki sposób mogę zastosować zarówno w tym samym czasie? mój UIRotationGestureRecognizer nie ma właściwości "scale", a mój UIPinchGestureRecognizer nie ma właściwości "rotation". I nie jestem pewien, które afery używałbym do robienia obu jednocześnie. – spentak

+0

Działa pięknie. Lepiej mieć tę wiedzę dzięki! – spentak

+0

Cieszę się, że mogę pomóc. BTW Zmieniłem ostatni fragment o tym, jak robić panoramowanie. Ponadto możesz umieścić w XIB identyfikatory gestów i nie musisz ich tworzyć za pomocą kodu w 'viewDidLoad'. Wystarczy przeciągnąć urządzenie rozpoznające na widok, a następnie podłączyć uczestnika i punkty akcji urządzenia rozpoznającego z przeciągnięciami kontrolnymi z urządzenia rozpoznającego do właściciela pliku. –

8

Aby to się stało, należy zaimplementować gest delegata shouldRecognizeSimultaneouslyWithGestureRecognizer i określić, które gesty mają być rozpoznawane jednocześnie.

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

Ten kod należy zmodyfikować do widoku, dla którego chcesz jednocześnie rozpoznawać gesty. Powyższy kod jest tym, czego potrzebujesz.

+0

Ma już 'shouldRecognizeSimultaneouslyWithGestureRecognizer:', który zawsze zwraca TAK. –

6

Swift 3 z przesuwać, obracać i 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 
    } 
+0

Testowałeś to? –

+0

@RoiMulia na pewno. Używanie go w prawdziwej aplikacji (jeszcze nie w prod). Co jest nie tak? –

+0

Hej Mike, przepraszam za stres. Nic złego. Chciałem tylko zapytać, czy jest już przetestowany, aby upewnić się, że jest bezpieczny w użyciu (na wypadek, gdy opuściłem kilka końcowych scenariuszy) –