iOS 使用手势UIGestureRecognizer对图像进行缩放、移动、旋转等操作
UIGestureRecognizer 类
该类拥有一系列子类,每个子类都用于识别某类指定的手势。它们是:
- UITapGestureRecognizer – “轻击”手势。可以配置为“单击”和“连击”的识别。
- UIPinchGestureRecognizer –“捏合”手势。该手势通常用于缩放视图或改变可视组件的大小。
- UIPanGestureRecognizer – “平移”手势。识别拖拽或移动动作。
- UISwipeGestureRecognizer – “轻扫”手势。当用户从屏幕上划过时识别为该手势。可以指定该动作的方向(上、下、左、右)。
- UIRotationGestureRecognizer – “转动”手势。用户两指在屏幕上做相对环形运动。
- UILongPressGestureRecognizer – “长按”手势。使用一指或多指触摸屏幕并保持一定时间。
这些手势识别器必需和视图通过addGestureRecognizer:方法联系在一起。识别器必需指定一个响应方法以便发生指定手势时进行调用。removeGestureRecognizer:方法可以将识别器从视图中移出,方法参数指定要移除的识别器。
下面通过一个实例程序来分别介绍这些手势,在一个视图中增加一个UIImageView控件,添加一个图像。对图像的操作都基于此视图中进行。分别对这个图像使用这些手势。
一、首先在一个视图中添加一个imageview控件,用以添加一个图像。
[cpp]
1. self.productImageView.image = [UIImage imageNamed:@"iPhone.jpg"];
二、tap 手势 (轻击)
说明:在单击中,实现的是视图恢复,在双击中实现的是视图放大/缩小一倍。
[cpp]
1. //轻点
2.
3. // 单击
4. UITapGestureRecognizer *SingleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resetImage:)];
5. //tap次数
6. [self.view addGestureRecognizer:SingleTapGesture];
7. // 双击
8. UITapGestureRecognizer *doubleTapGesture;
9. doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapFrom)];
10. doubleTapGesture.numberOfTapsRequired = 2;
11. [self.view addGestureRecognizer:doubleTapGesture];
12. // 关键在这一行,如果双击确定偵測失败才會触发单击
13. [SingleTapGesture requireGestureRecognizerToFail:doubleTapGesture];
响应方法
[cpp]
1. //单击恢复视图
2. - (void)resetImage:(UITapGestureRecognizer *)recognizer
3. {
4. [UIView beginAnimations:nil context:nil];
5. [UIView setAnimationDuration:0.3];
6. // 恒等变换. beginAnimation 和 commitAnimation 间的操作为动画过程
7. self.productImageView.transform = CGAffineTransformIdentity;
8. [self.productImageView setCenter:CGPointMake(self.view.frame.size.height/2, self.view.frame.size.width/2)];
9. [UIView commitAnimations];
10. }
11.
12. //双击实现放大和缩小一倍
13. - (void) handleDoubleTapFrom {
14. if (flag == YES) {
15. [UIView beginAnimations:nil context:nil];
16. [UIView setAnimationDuration:0.3];
17.
18. [self.productImageView setFrame:CGRectMake(
19. self.productImageView.frame.origin.x -self.productImageView.frame.size.width / 2,
20. self.productImageView.frame.origin.y - self.productImageView.frame.size.height / 2,
21. 2 * self.productImageView.frame.size.width,
22. 2 * self.productImageView.frame.size.height)];
23. [UIView commitAnimations];
24. flag = NO;
25. }
26. else {
27. [UIView beginAnimations:nil context:nil];
28. [UIView setAnimationDuration:0.3];
29. [self.productImageView setFrame:CGRectMake(self.productImageView.frame.origin.x+self.productImageView.frame.size.width/4, self.productImageView.frame.origin.y + self.productImageView.frame.size.height/4, self.productImageView.frame.size.width/2, self.productImageView.frame.size.height/2)];
30. [UIView commitAnimations];
31. flag = YES;
32. }
33. }
特别说明这个语句:
[cpp]
1. [SingleTapGesture requireGestureRecognizerToFail:doubleTapGesture];
有些手势其实是互相关联的,例如 Tap 与 LongPress、Swipe与 Pan,或是 Tap 一次与Tap 兩次。当一個 UIView 同时添加兩个相关联的手势时,到底我这一下手指头按的要算是 Tap 还是 LongPress?如果照预设作法来看,只要先满足条件的就会跳出并呼叫对应方法,举例来说,如果同时注册了 Pan 和 Swipe,只要手指头一移动就会触发 Pan 然后跳出,因而永远都不會发生 Swipe;单点与双点的情形也是一样,永远都只会触发单点,不會有双点。
那么这个问题有解吗?答案是肯定的,UIGestureRecognizer 有个方法叫做requireGestureRecognizerToFail,他可以指定某一个 recognizer,即便自己已经满足條件了,也不會立刻触发,会等到该指定的 recognizer 确定失败之后才触发。
二、pinch 手势 (捏合缩放)
说明:在模拟器中 按住alt+鼠标左键即可出现双指触摸屏幕。
[cpp]
1. //捏合缩放
2. UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)];
3. [self.view addGestureRecognizer:pinchGesture];
响应方法 (以下提供了两种缩放响应方法)
[cpp]
1. // 处理捏合缩放手势
2. - (void) pinchView:(UIPinchGestureRecognizer *)pinchGestureRecognizer
3. {
4. UIView *view = self.productImageView;
5. if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan || pinchGestureRecognizer.state == UIGestureRecognizerStateChanged) {
6. view.transform = CGAffineTransformScale(view.transform, pinchGestureRecognizer.scale, pinchGestureRecognizer.scale);
7. pinchGestureRecognizer.scale = 1;
8. }
9. }
[cpp]
1. - (void)scaleImage:(UIPinchGestureRecognizer *)recognizer
2. {
3. if([recognizer state] == UIGestureRecognizerStateEnded) {
4. // 如果Pinch 手势结束,重置 previousScale 为 1.0
5. self.previousScale = 1.0;
6. return;
7. }
8. CGFloat newScale = [recognizer scale]-self.previousScale +1.0;
9. CGAffineTransform currentTransformation = self.productImageView.transform;
10. // CGAffineTransformScale(currentTransformation, 1, 1) 变换保持原大小
11. CGAffineTransform newTransform = CGAffineTransformScale(currentTransformation, newScale, newScale);
12. // perform the new transform
13. self.productImageView.transform = newTransform;
14. self.previousScale = [recognizer scale];
15. }
三、pan 手势 (平移)
[cpp]
1. //平移
2. UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)];
3. [panGesture setMinimumNumberOfTouches:1];
4. [panGesture setMaximumNumberOfTouches:1];
5. [self.view addGestureRecognizer:panGesture];
响应方法
[cpp]
1. // 处理拖拉手势
2. - (void) panView:(UIPanGestureRecognizer *)panGestureRecognizer
3. {
4. UIView *view = self.productImageView;
5. if (panGestureRecognizer.state == UIGestureRecognizerStateBegan || panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
6. CGPoint translation = [panGestureRecognizer translationInView:view.superview];
7. [view setCenter:(CGPoint){view.center.x + translation.x, view.center.y + translation.y}];
8. [panGestureRecognizer setTranslation:CGPointZero inView:view.superview];
9. }
10. }
四、rotate 手势 (旋转)
[cpp]
1. //旋转
2. UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotateView:)];
3. [self.view addGestureRecognizer:rotationGesture];
响应方法
[cpp]
1. // 处理旋转手势
2. - (void) rotateView:(UIRotationGestureRecognizer *)rotationGestureRecognizer
3. {
4. UIView *view = self.productImageView;
5. if (rotationGestureRecognizer.state == UIGestureRecognizerStateBegan || rotationGestureRecognizer.state == UIGestureRecognizerStateChanged) {
6. view.transform = CGAffineTransformRotate(view.transform, rotationGestureRecognizer.rotation);
7. [rotationGestureRecognizer setRotation:0];
8. }
9. }
最后还有一个要处理的就是模拟器的横向摆放。
[cpp]
1. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
2. {
3. return ((interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft));
4. }
UIGestureRecognizer 类
该类拥有一系列子类,每个子类都用于识别某类指定的手势。它们是:
- UITapGestureRecognizer – “轻击”手势。可以配置为“单击”和“连击”的识别。
- UIPinchGestureRecognizer –“捏合”手势。该手势通常用于缩放视图或改变可视组件的大小。
- UIPanGestureRecognizer – “平移”手势。识别拖拽或移动动作。
- UISwipeGestureRecognizer – “轻扫”手势。当用户从屏幕上划过时识别为该手势。可以指定该动作的方向(上、下、左、右)。
- UIRotationGestureRecognizer – “转动”手势。用户两指在屏幕上做相对环形运动。
- UILongPressGestureRecognizer – “长按”手势。使用一指或多指触摸屏幕并保持一定时间。
这些手势识别器必需和视图通过addGestureRecognizer:方法联系在一起。识别器必需指定一个响应方法以便发生指定手势时进行调用。removeGestureRecognizer:方法可以将识别器从视图中移出,方法参数指定要移除的识别器。
下面通过一个实例程序来分别介绍这些手势,在一个视图中增加一个UIImageView控件,添加一个图像。对图像的操作都基于此视图中进行。分别对这个图像使用这些手势。
一、首先在一个视图中添加一个imageview控件,用以添加一个图像。
[cpp]
1. self.productImageView.image = [UIImage imageNamed:@"iPhone.jpg"];
二、tap 手势 (轻击)
说明:在单击中,实现的是视图恢复,在双击中实现的是视图放大/缩小一倍。
[cpp]
1. //轻点
2.
3. // 单击
4. UITapGestureRecognizer *SingleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resetImage:)];
5. //tap次数
6. [self.view addGestureRecognizer:SingleTapGesture];
7. // 双击
8. UITapGestureRecognizer *doubleTapGesture;
9. doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTapFrom)];
10. doubleTapGesture.numberOfTapsRequired = 2;
11. [self.view addGestureRecognizer:doubleTapGesture];
12. // 关键在这一行,如果双击确定偵測失败才會触发单击
13. [SingleTapGesture requireGestureRecognizerToFail:doubleTapGesture];
响应方法
[cpp]
1. //单击恢复视图
2. - (void)resetImage:(UITapGestureRecognizer *)recognizer
3. {
4. [UIView beginAnimations:nil context:nil];
5. [UIView setAnimationDuration:0.3];
6. // 恒等变换. beginAnimation 和 commitAnimation 间的操作为动画过程
7. self.productImageView.transform = CGAffineTransformIdentity;
8. [self.productImageView setCenter:CGPointMake(self.view.frame.size.height/2, self.view.frame.size.width/2)];
9. [UIView commitAnimations];
10. }
11.
12. //双击实现放大和缩小一倍
13. - (void) handleDoubleTapFrom {
14. if (flag == YES) {
15. [UIView beginAnimations:nil context:nil];
16. [UIView setAnimationDuration:0.3];
17.
18. [self.productImageView setFrame:CGRectMake(
19. self.productImageView.frame.origin.x -self.productImageView.frame.size.width / 2,
20. self.productImageView.frame.origin.y - self.productImageView.frame.size.height / 2,
21. 2 * self.productImageView.frame.size.width,
22. 2 * self.productImageView.frame.size.height)];
23. [UIView commitAnimations];
24. flag = NO;
25. }
26. else {
27. [UIView beginAnimations:nil context:nil];
28. [UIView setAnimationDuration:0.3];
29. [self.productImageView setFrame:CGRectMake(self.productImageView.frame.origin.x+self.productImageView.frame.size.width/4, self.productImageView.frame.origin.y + self.productImageView.frame.size.height/4, self.productImageView.frame.size.width/2, self.productImageView.frame.size.height/2)];
30. [UIView commitAnimations];
31. flag = YES;
32. }
33. }
特别说明这个语句:
[cpp]
1. [SingleTapGesture requireGestureRecognizerToFail:doubleTapGesture];
有些手势其实是互相关联的,例如 Tap 与 LongPress、Swipe与 Pan,或是 Tap 一次与Tap 兩次。当一個 UIView 同时添加兩个相关联的手势时,到底我这一下手指头按的要算是 Tap 还是 LongPress?如果照预设作法来看,只要先满足条件的就会跳出并呼叫对应方法,举例来说,如果同时注册了 Pan 和 Swipe,只要手指头一移动就会触发 Pan 然后跳出,因而永远都不會发生 Swipe;单点与双点的情形也是一样,永远都只会触发单点,不會有双点。
那么这个问题有解吗?答案是肯定的,UIGestureRecognizer 有个方法叫做requireGestureRecognizerToFail,他可以指定某一个 recognizer,即便自己已经满足條件了,也不會立刻触发,会等到该指定的 recognizer 确定失败之后才触发。
二、pinch 手势 (捏合缩放)
说明:在模拟器中 按住alt+鼠标左键即可出现双指触摸屏幕。
[cpp]
1. //捏合缩放
2. UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)];
3. [self.view addGestureRecognizer:pinchGesture];
响应方法 (以下提供了两种缩放响应方法)
[cpp]
1. // 处理捏合缩放手势
2. - (void) pinchView:(UIPinchGestureRecognizer *)pinchGestureRecognizer
3. {
4. UIView *view = self.productImageView;
5. if (pinchGestureRecognizer.state == UIGestureRecognizerStateBegan || pinchGestureRecognizer.state == UIGestureRecognizerStateChanged) {
6. view.transform = CGAffineTransformScale(view.transform, pinchGestureRecognizer.scale, pinchGestureRecognizer.scale);
7. pinchGestureRecognizer.scale = 1;
8. }
9. }
[cpp]
1. - (void)scaleImage:(UIPinchGestureRecognizer *)recognizer
2. {
3. if([recognizer state] == UIGestureRecognizerStateEnded) {
4. // 如果Pinch 手势结束,重置 previousScale 为 1.0
5. self.previousScale = 1.0;
6. return;
7. }
8. CGFloat newScale = [recognizer scale]-self.previousScale +1.0;
9. CGAffineTransform currentTransformation = self.productImageView.transform;
10. // CGAffineTransformScale(currentTransformation, 1, 1) 变换保持原大小
11. CGAffineTransform newTransform = CGAffineTransformScale(currentTransformation, newScale, newScale);
12. // perform the new transform
13. self.productImageView.transform = newTransform;
14. self.previousScale = [recognizer scale];
15. }
三、pan 手势 (平移)
[cpp]
1. //平移
2. UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)];
3. [panGesture setMinimumNumberOfTouches:1];
4. [panGesture setMaximumNumberOfTouches:1];
5. [self.view addGestureRecognizer:panGesture];
响应方法
[cpp]
1. // 处理拖拉手势
2. - (void) panView:(UIPanGestureRecognizer *)panGestureRecognizer
3. {
4. UIView *view = self.productImageView;
5. if (panGestureRecognizer.state == UIGestureRecognizerStateBegan || panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
6. CGPoint translation = [panGestureRecognizer translationInView:view.superview];
7. [view setCenter:(CGPoint){view.center.x + translation.x, view.center.y + translation.y}];
8. [panGestureRecognizer setTranslation:CGPointZero inView:view.superview];
9. }
10. }
四、rotate 手势 (旋转)
[cpp]
1. //旋转
2. UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotateView:)];
3. [self.view addGestureRecognizer:rotationGesture];
响应方法
[cpp]
1. // 处理旋转手势
2. - (void) rotateView:(UIRotationGestureRecognizer *)rotationGestureRecognizer
3. {
4. UIView *view = self.productImageView;
5. if (rotationGestureRecognizer.state == UIGestureRecognizerStateBegan || rotationGestureRecognizer.state == UIGestureRecognizerStateChanged) {
6. view.transform = CGAffineTransformRotate(view.transform, rotationGestureRecognizer.rotation);
7. [rotationGestureRecognizer setRotation:0];
8. }
9. }
最后还有一个要处理的就是模拟器的横向摆放。
[cpp]
1. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
2. {
3. return ((interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft));
4. }