Detecting touches used to be a chore. Thanks to the UIGestureRecognizer family of classes, detecting touches & gestures is a breeze. In this episode we implement a Photo Table where you can add photos, move them around, as well as pinch & rotate.
Episode Links Episode source code Event Handling Guide for iOS - Gesture Recognizers UIGestureRecognizer Class Reference Adding a Photo with a Double Tap UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onViewDoubleTap:)]; tapRecognizer.numberOfTapsRequired = 2; [self.view addGestureRecognizer:tapRecognizer]; - (void)onViewDoubleTap:(UITapGestureRecognizer *)tap { CGPoint touchCenter = [tap locationInView:self.view]; UIImageView *imageView = [[UIImageView alloc] initWithImage:[self nextImage]]; CGRect imageViewFrame = CGRectMake(0, 0, 200, 200); imageViewFrame.origin = CGPointMake(touchCenter.x - imageViewFrame.size.width / 2.0f, touchCenter.y - imageViewFrame.size.height / 2.0f); imageView.frame = imageViewFrame; imageView.layer.borderWidth = 4; imageView.layer.borderColor = [[UIColor whiteColor] CGColor]; imageView.layer.shadowColor = [[UIColor blackColor] CGColor]; imageView.layer.shadowOffset = CGSizeMake(0, 1); CGMutablePathRef shadowPath = CGPathCreateMutable(); CGAffineTransform transform = imageView.transform; CGPathAddRect(shadowPath, &transform, imageView.bounds); imageView.layer.shadowOpacity = 0.5; imageView.layer.shadowPath = shadowPath; CGPathRelease(shadowPath); imageView.alpha = 0.75; imageView.transform = CGAffineTransformMakeScale(1.25, 1.25); CGFloat angle = DEGREES_TO_RADIANS((arc4random() % 10) - 5); imageView.transform = CGAffineTransformRotate(imageView.transform, angle); [self.view addSubview:imageView]; [UIView animateWithDuration:0.25 animations:^{ imageView.alpha = 1; imageView.transform = CGAffineTransformIdentity; }]; [self addGestureRecognizersToView:imageView]; } - (void)addGestureRecognizersToView:(UIView *)view { view.userInteractionEnabled = YES; //... } Moving pictures around We just need to add a pan recognizer to each image view. In the callback, we'll just offset the center point of the image by the location of the touch. - (void)addGestureRecognizersToView:(UIView *)view { //... UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onPan:)]; panRecognizer.delegate = self; [view addGestureRecognizer:panRecognizer]; //... } - (void)onPan:(UIPanGestureRecognizer *)pan { CGPoint offset = [pan translationInView:self.view]; CGPoint center = pan.view.center; center.x += offset.x; center.y += offset.y; pan.view.center = center; [pan setTranslation:CGPointZero inView:self.view]; } Note that once we have accounted for the translation amount, we have to "zero it out" so that it won't affect the next callbacks. If we do not, the translation amount will be cumulative and the view will eventually slide out from under your finger. Pinching to scale the image - (void)addGestureRecognizersToView:(UIView *)view { //... UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onPinch:)]; pinchRecognizer.delegate = self; [view addGestureRecognizer:pinchRecognizer]; //... } - (void)onPinch:(UIPinchGestureRecognizer *)pinch { CGFloat scale = [pinch scale]; UIView *view = pinch.view; view.transform = CGAffineTransformScale(view.transform, scale, scale); [pinch setScale:1]; } Here, we again "zero out" the scale by setting it to one after we have used the scale to alter the view's transform. Rotating the images Rotating is similar to pinching to resize... - (void)addGestureRecognizersToView:(UIView *)view { //... UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(onRotate:)]; rotationRecognizer.delegate = self; [view addGestureRecognizer:rotationRecognizer]; //... } - (void)onRotate:(UIRotationGestureRecognizer *)rotation { CGFloat angle = [rotation rotation]; rotation.view.transform = CGAffineTransformRotate(rotation.view.transform, angle); [rotation setRotation:0]; } Allowing simultaneous gestures By default, while one recognizer is active, the others won't work. To get around this, you have to mark the class as conforming to the UIGestureRecognizerDelegate protocol and set each gesture recognizers delegate property to self. The you can implement this method: - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } Now you can pinch, rotate & pan at the same time! Try panning multiple images at once as well.