Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Pinch Scale and Two Finger Rotate at same time

Here is my code:

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; 

Code For Pinches and Rotates:

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

My rotation works great on its own and my scale works great on its own, but they wont work together. One always works or the other doesn't. When I implement shouldRecognizeSimultaneouslyWithGestureRecognizer the two gestures seem to fight against each other and produce poor results. What am I missing? (Yes I have implemented <UIGestureRecognizerDelegate>)

like image 344
spentak Avatar asked Nov 13 '11 00:11

spentak


1 Answers

Every time pinch: is called, you just compute the transform based on the pinch recognizer's scale. Every time pinchRotate: is called, you just compute the transform based on the rotation recognizer's rotation. You never combine the scale and the rotation into one transform.

Here's an approach. Give yourself one new instance variable, _activeRecognizers:

NSMutableSet *_activeRecognizers; 

Initialize it in viewDidLoad:

_activeRecognizers = [NSMutableSet set]; 

Use one method as the action for both recognizers:

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

You'll need this helper method:

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

This works if you're just allowing rotating and scaling. (I even tested it!)

If you want to add panning, use a separate action method and just adjust selectedImage.center. Trying to do panning with rotation and scaling using selectedImage.transform is much more complicated.

like image 139
rob mayoff Avatar answered Oct 04 '22 11:10

rob mayoff