- Touch Tutorial - Part One (touchesEnded Event)
- Touch Tutorial - Part Two (touchesBegan Event)
- Touch Tutorial - Part Three (Zoom In/Out)
- TouchTutorial - Part Four (pan left/right)
In this tutorial, I will show you how to use the touchesMoved event to zoom in and out the image on the UIImageView. Now, I have not exactly figured out a way to actually zoom in and out the actual image but here is the code on when to zoom in and zoom out. If anyone has figured out a way to zoom in/out the actual image, please share it everyone.
Before we can implement the touchesMoved event, we are going to declare some variables and methods in ImgViewController.h file. This is how the header file is going to look like
#import <UIKit/UIKit.h>
@interface ImgViewController : UIViewController {
IBOutlet UIImageView *imgView;
NSTimer *timer;
CGFloat initialDistance;
}
- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint;
- (void) clearTouches;
@end
@interface ImgViewController : UIViewController {
IBOutlet UIImageView *imgView;
NSTimer *timer;
CGFloat initialDistance;
}
- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint;
- (void) clearTouches;
@end
disanceBetweenTwoPoints is used to calculate as the method name implies, distance between two points. initialDistance is used to keep track of the distance when touchesBegan method is fired. To zoom in and zoom out, we first need to calculate the distance between the two fingers and store it in initialDistance variable. This is how the touchesBegan method will look like.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
switch ([allTouches count]) {
case 1: { //Single touch
//Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
switch ([touch tapCount])
{
case 1: //Single Tap.
{
//Start a timer for 2 seconds.
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self
selector:@selector(showAlertView:) userInfo:nil repeats:NO];
[timer retain];
} break;
case 2: {//Double tap.
//Track the initial distance between two fingers.
UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];
initialDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:[self view]]
toPoint:[touch2 locationInView:[self view]]];
} break;
}
} break;
case 2: { //Double Touch
} break;
default:
break;
}
}
NSSet *allTouches = [event allTouches];
switch ([allTouches count]) {
case 1: { //Single touch
//Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
switch ([touch tapCount])
{
case 1: //Single Tap.
{
//Start a timer for 2 seconds.
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self
selector:@selector(showAlertView:) userInfo:nil repeats:NO];
[timer retain];
} break;
case 2: {//Double tap.
//Track the initial distance between two fingers.
UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];
initialDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:[self view]]
toPoint:[touch2 locationInView:[self view]]];
} break;
}
} break;
case 2: { //Double Touch
} break;
default:
break;
}
}
We get the first touch objects at index 0 and 1 and then we calculate the initial distance between the two points. This is how the distanceBetweenTwoPoints method looks like
- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint {
float x = toPoint.x - fromPoint.x;
float y = toPoint.y - fromPoint.y;
return sqrt(x * x + y * y);
}
float x = toPoint.x - fromPoint.x;
float y = toPoint.y - fromPoint.y;
return sqrt(x * x + y * y);
}
In touchesMoved event, we find out if there are at least two touches on the screen. We then get the touch object at index 0 and 1, calculate the distance between the finalDistance and the initialDistance. If the initialDistance is greater then the finalDistance then we know that the image is being zoomed out else the image is being zoomed in. This is how the source code looks like
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if([timer isValid])
[timer invalidate];
NSSet *allTouches = [event allTouches];
switch ([allTouches count])
{
case 1: {
} break;
case 2: {
//The image is being zoomed in or out.
UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];
//Calculate the distance between the two fingers.
CGFloat finalDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:[self view]]
toPoint:[touch2 locationInView:[self view]]];
//Check if zoom in or zoom out.
if(initialDistance > finalDistance) {
NSLog(@"Zoom Out");
}
else {
NSLog(@"Zoom In");
}
} break;
}
}
if([timer isValid])
[timer invalidate];
NSSet *allTouches = [event allTouches];
switch ([allTouches count])
{
case 1: {
} break;
case 2: {
//The image is being zoomed in or out.
UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];
//Calculate the distance between the two fingers.
CGFloat finalDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:[self view]]
toPoint:[touch2 locationInView:[self view]]];
//Check if zoom in or zoom out.
if(initialDistance > finalDistance) {
NSLog(@"Zoom Out");
}
else {
NSLog(@"Zoom In");
}
} break;
}
}
NSLog tells us if what we are doing is correct or not. If someone knows how to zoom in/out an actual image, please let me know.
Since we keep track of the initialDistance, we need to clear that value when touches is canceled or when touches are ended. We do this in clearTouches method, which is called from touchesEnded event and touchesCanceled event. This is how the method looks like
- (void)clearTouches {
initialDistance = -1;
}
initialDistance = -1;
}
I hope you found this tutorial a little helpful without the actual zoom in/out functionality. You can download the source code here and please leave me your comments.
Happy Programming,
iPhone SDK Articles

6 comments:
You have two bugs I found:
1> The count1 and count2 new code is in the wrong part of the switch statement.
2> The comparison of initial distance is reverse of what it should be.
I think...
Your tutorials are very useful.
It's very irritating that the SDK doesn't provide a uniform way to read/understand gestures (at least as a starting point), as it is so key to the user's experience and to consistency across apps.
Hi,
I am working on something similar to wat u just explained in the tutorial 3. I m not sure but i think u can try out zooming in and out using CGImageRef objects. You can create a local object from [uiImageObject CGImage] Message. Then u can probably adjust the data to view by using a clipping rectangle in the CGImageCreateWithImageInRect function. Check it out in the reference. Might work for u.
Actually, I think the right way to do the zoomable UIImageView is to place it in UIScrollView subview, which will handle pinch action automatically. Anyway, you'll have to implement the double-tab action (zoom in and out or whatever) yourself.
Thanks for the tutorial anyway. It's been really helpful.
The right way to zoom a UIImageView is to manipulate the frame property.
UIImageView.frame is a CGRect that consists of four CGFloat values; the x and y co-ordinate of the top left corner, and the width and height of the image being displayed.
So UIImageView.frame.origin.x and .y and UIImageView.frame.size.width and .height are the elements, although you can only manipulate the frame as a whole: so
UIImageView.frame = CGRectMake(x,y,new w, new h);
would set the position and the size at the same time.
Thank you so much, this is incredibly helpful, and with just 2 minor changes, works like a charm.
The offending code I found was lines 130-138, and if you simply flip the > to a < (as shown), then add the line "initialDistance = finalDistance;" to the bottom of the statement, you get a view that very accurately tells you which direction the user gesture is going.
//Check if zoom in or zoom out.
if(initialDistance < finalDistance) {
NSLog(@"Zoom Out");
}
else
{
NSLog(@"Zoom In");
}
initialDistance = finalDistance;
--
I really do think it is absurd that Apple has taken until 3.0 to release a standard way to do this cross-app, and not having worked with the new API, I can't speak to it with personal experience.
Regardless, thank you for this, I really appreciate it.
Thanks
Ryan
http://rcloudsoftware.wordpress.com
Post a Comment