標籤:手勢識別 ios開發
在 iPhone 或 iPad 的開發中,除了用 touchesBegan / touchesMoved / touchesEnded 這組方法來控制使用者的手指觸控外,也可以用 UIGestureRecognizer 的衍生類別來進行判斷。用 UIGestureRecognizer 的好處在於有現成的手勢,開發人員不用自己計算手指移動軌跡。UIGestureRecognizer的衍生類別有以下幾種:
UITapGestureRecognizer
UIPinchGestureRecognizer
UIRotationGestureRecognizer
UISwipeGestureRecognizer
UIPanGestureRecognizer
UILongPressGestureRecognizer
從命名上不難瞭解這些類別所對應代表的手勢,分別是 Tap(點一下)、Pinch(二指往內或往撥出動)、Rotation(旋轉)、Swipe(滑動,快速移動)、Pan (拖移,慢速移動)以及 LongPress(長按)。這些手勢別在使用上也很簡單,只要在使用前定義並添加到對應的視圖上即可。
複製代碼
// 定義一個 recognizer, 並加到需要偵測該手勢的 UIView 元件上
- (void)viewDidLoad {
UISwipeGestureRecognizer* recognizer;
// handleSwipeFrom 是偵測到手勢,所要呼叫的方法
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:selfaction:@selector(handleSwipeFrom)];
// 不同的 Recognizer 有不同的實體變數
// 例如 SwipeGesture 可以指定方向
// 而 TapGesture 則可以指定次數
recognizer.direction = UISwipeGestureRecognizerDirectionUp
[self.view addGestureRecognizer:recognizer];
[recognizer release];
}
- (void)handleSwipeFrom:(UISwipeGestureRecognizer*)recognizer {
// 觸發手勢事件後,在這裡作些事情
// 底下是刪除手勢的方法
[self.view removeGestureRecognizer:recognizer];
}
複製代碼
問題來了。有些手勢其實是互相關聯的,例如 Tap 與 LongPress、Swipe與 Pan,或是 Tap 一次與Tap 兩次。當一個 UIView 同時添加兩個相關聯的手勢時,到底我這一下手指頭按的要算是 Tap 還是 LongPress?如果照預設作法來看,只要「先滿足條件」的就會跳出並呼叫對應方法,舉例來說,如果同時註冊了 Pan 和 Swipe,只要手指頭一移動就會觸發 Pan 然後跳出,因而永遠都不會發生 Swipe;單點與雙點的情形也是一樣,永遠都只會觸發單點,不會有雙點。
那麼這個問題有解嗎?答案是肯定的,UIGestureRecognizer 有個方法叫做requireGestureRecognizerToFail,他可以指定某一個 recognizer,即便自己已經滿足條件了,也不會立刻觸發,會等到該指定的 recognizer 確定失敗之後才觸發。以同時支援單點與雙點的手勢為例,代碼如下:
複製代碼
- (void)viewDidLoad {
// 單擊的 Recognizer
UITapGestureRecognizer* singleRecognizer;
singleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(handleSingleTapFrom)];
singleTapRecognizer.numberOfTapsRequired = 1; // 單擊
[self.view addGestureRecognizer:singleRecognizer];
// 雙擊的 Recognizer
UITapGestureRecognizer* double;
doubleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(handleDoubleTapFrom)];
doubleTapRecognizer.numberOfTapsRequired = 2; // 雙擊
[self.view addGestureRecognizer:doubleRecognizer];
// 關鍵在這一行,如果雙擊確定偵測失敗才會觸發單擊
[singleRecognizer requireGestureRecognizerToFail:doubleRecognizer];
[singleRecognizer release];
[doubleRecognizer release];
}
Demo
首先建立一個基於Sigle view Application的項目,名為GestureTest;我的項目結構如下:
往viewController.xib檔案裡拖動一個imageView,並使覆蓋整個螢幕,改動屬性為:
viewController.h檔案:
1. #import <UIKit/UIKit.h>
2.
3. @interface ViewController : UIViewController{
4. IBOutlet UIImageView *imageView;
5. }
6. @property (nonatomic,retain)IBOutlet UIImageView *imageView;
7. @end
並使xib檔案裡的imageView與之串連;
然後是viewController.m檔案的實現部分:
1. @synthesize imageView;
2.
3. CGFloat lastScaleFactor=1;//放大、縮小
4. CGFloat netRotation;//旋轉
5. CGPoint netTranslation;//平衡
6. NSArray *images;//圖片數組
7. int imageIndex=0;//數組下標
8.
9. - (void)viewDidLoad
10. {
11. //1、建立手勢執行個體,並串連方法handleTapGesture,點選手勢
12. UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTapGesture:)];
13. //設定手勢點擊數,雙擊:點2下
14. tapGesture.numberOfTapsRequired=2;
15. // imageView添加手勢識別
16. [imageView addGestureRecognizer:tapGesture];
17. //釋放記憶體
18. [tapGesture release];
19.
20. //2、手勢為捏的姿勢:按住option按鈕配合滑鼠來做這個動作在虛擬器上
21. UIPinchGestureRecognizer *pinchGesture=[[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchGesture:)];
22. [imageView addGestureRecognizer:pinchGesture];//imageView添加手勢識別
23. [pinchGesture release];
24.
25. //3、旋轉手勢:按住option按鈕配合滑鼠來做這個動作在虛擬器上
26. UIRotationGestureRecognizer *rotateGesture=[[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(handleRotateGesture:)];
27. [imageView addGestureRecognizer:rotateGesture];
28. [rotateGesture release];
29.
30. //4、拖手勢
31. UIPanGestureRecognizer *panGesture=[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(handlePanGesture:)];
32. // [imageView addGestureRecognizer:panGesture];
33. [panGesture release];
34.
35. //5、划動手勢
36. images=[[NSArray alloc]initWithObjects:@"cell.jpg",@"heihua.jpg",@"xuanyi.jpg", nil];
37. //右劃
38. UISwipeGestureRecognizer *swipeGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeGesture:)];
39. [imageView addGestureRecognizer:swipeGesture];
40. [swipeGesture release];
41. //左劃
42. UISwipeGestureRecognizer *swipeLeftGesture=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeGesture:)];
43. swipeGesture.direction=UISwipeGestureRecognizerDirectionLeft;//不設定黑夜是右
44. [imageView addGestureRecognizer:swipeLeftGesture];
45. [swipeLeftGesture release];
46.
47. //6、長按手勢
48. UILongPressGestureRecognizer *longpressGesutre=[[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongpressGesture:)];
49. //長按時間為1秒
50. longpressGesutre.minimumPressDuration=1;
51. //允許15秒中運動
52. longpressGesutre.allowableMovement=15;
53. //所需觸摸1次
54. longpressGesutre.numberOfTouchesRequired=1;
55. [imageView addGestureRecognizer:longpressGesutre];
56. [longpressGesutre release];
57.
58. [super viewDidLoad];
59. // Do any additional setup after loading the view, typically from a nib.
60. }
61. //雙擊螢幕時會調用此方法,放大和縮小圖片
62. -(IBAction)handleTapGesture:(UIGestureRecognizer*)sender{
63. //判斷imageView的內容模式是否是UIViewContentModeScaleAspectFit,該模式是原比例,按照圖片原時比例顯示大小
64. if(sender.view.contentMode==UIViewContentModeScaleAspectFit){
65. //把imageView模式改成UIViewContentModeCenter,按照圖片原先的大小顯示中心的一部分在imageView
66. sender.view.contentMode=UIViewContentModeCenter;
67. }else{
68. sender.view.contentMode=UIViewContentModeScaleAspectFit;
69. }
70. }
71. //捏的手勢,使圖片放大和縮小,捏的動作是一個連續的動作
72. -(IBAction)handlePinchGesture:(UIGestureRecognizer*)sender{
73. //得到sender捏手勢的大小
74. CGFloat factor=[(UIPinchGestureRecognizer*)sender scale];
75. if(factor>1){
76. //圖片放大
77. sender.view.transform=CGAffineTransformMakeScale(lastScaleFactor+(factor-1), (lastScaleFactor+(factor-1)));
78.
79. }else{
80. //縮小
81. sender.view.transform=CGAffineTransformMakeScale(lastScaleFactor*factor, lastScaleFactor*factor);
82.
83. }
84. //狀態是否結束,如果結束儲存資料
85. if(sender.state==UIGestureRecognizerStateEnded){
86. if(factor>1){
87. lastScaleFactor+=(factor-1);
88. }else{
89. lastScaleFactor*=factor;
90. }
91. }
92. }
93. //旋轉手勢
94. -(IBAction)handleRotateGesture:(UIGestureRecognizer*)sender{
95. //浮點類型,得到sender的旋轉度數
96. CGFloat rotation=[(UIRotationGestureRecognizer*)sender rotation];
97. //旋轉角度CGAffineTransformMakeRotation
98. CGAffineTransform transform=CGAffineTransformMakeRotation(rotation+netRotation);
99. //改變映像角度
100. sender.view.transform=transform;
101. //狀態結束,儲存資料
102. if(sender.state==UIGestureRecognizerStateEnded){
103. netRotation+=rotation;
104. }
105.
106. }
107. //拖手勢
108. -(IBAction)handlePanGesture:(UIGestureRecognizer*)sender{
109. //得到拖的過程中的xy座標
110. CGPoint translation=[(UIPanGestureRecognizer*)sender translationInView:imageView];
111. //平移圖片CGAffineTransformMakeTranslation
112. sender.view.transform=CGAffineTransformMakeTranslation(netTranslation.x+translation.x, netTranslation.y+translation.y);
113. //狀態結束,儲存資料
114. if(sender.state==UIGestureRecognizerStateEnded){
115. netTranslation.x+=translation.x;
116. netTranslation.y+=translation.y;
117. }
118.
119. }
120. //划動手勢
121. -(IBAction)handleSwipeGesture:(UIGestureRecognizer*)sender{
122. //划動的方向
123. UISwipeGestureRecognizerDirection direction=[(UISwipeGestureRecognizer*) sender direction];
124. //判斷是上下左右
125. switch (direction) {
126. case UISwipeGestureRecognizerDirectionUp:
127. NSLog(@"up");
128. break;
129. case UISwipeGestureRecognizerDirectionDown:
130. NSLog(@"down");
131. break;
132. case UISwipeGestureRecognizerDirectionLeft:
133. NSLog(@"left");
134. imageIndex++;//下標++
135. break;
136. case UISwipeGestureRecognizerDirectionRight:
137. NSLog(@"right");
138. imageIndex--;//下標--
139. break;
140. default:
141. break;
142. }
143. //得到不越界不<0的下標
144. imageIndex=(imageIndex<0)?([images count]-1):imageIndex%[images count];
145. //imageView顯示圖片
146. imageView.image=[UIImage imageNamed:[images objectAtIndex:imageIndex]];
147.
148. }
149. //長按手勢
150. -(IBAction)handleLongpressGesture:(UIGestureRecognizer*)sender{
151. //建立警告
152. UIActionSheet *actionSheet=[[UIActionSheet alloc]initWithTitle:@"Image options" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:@"Save Image",@"Copy", nil];
153. //當前view顯示警告
154. [actionSheet showInView:self.view];
155. [actionSheet release];
156. }
157. -(void)dealloc{
158. [images release];
159. [imageView release];
160. [super dealloc];
161. }
iOS 手勢UIGestureRecognizer