手勢識別在 iOS 中非常重要,他極大地提高了移動設備的使用便捷性。iOS 系統在 3.2 以後,他提供了一些常用的手勢(UIGestureRecognizer 的子類),開發者可以直接使用他們進行手勢操作。 手勢類型(他們都繼承自UIGestureRecognizer,而UIGestureRecognizer繼承自NSObject)
UIPanGestureRecognizer(拖動) UIPinchGestureRecognizer(捏合) UIRotationGestureRecognizer(旋轉) UITapGestureRecognizer(點按) UILongPressGestureRecognizer(長按) ?UISwipeGestureRecognizer(輕掃)代碼實戰的時候,通常繼承 UIGestureRecognizer 類,實現自定義手勢(手勢識別器類)一般設計成單利對象。因為事件傳遞如果是通過Block或者是代理,那麼如果超過識別器的生命周期,手勢將不能正常響應(具體看github代碼)
1.手勢識別是具有互斥的原則的,比如單擊和雙擊,如果它識別出一種手勢,其後的手勢將不被識別。所以對於關聯手勢,要做特殊處理以幫助程序甄別,應該把當前手勢歸結到哪一類手勢裡面。
2.比如,單擊和雙擊並存時,如果不做處理,它就只能發送出單擊的消息。為了能夠識別出雙擊手勢,就需要做一個特殊處理邏輯,即先判斷手勢是否是雙擊,在雙擊失效的情況下作為單擊手勢處理。使用
[A requireGestureRecognizerToFail:B]函數,它可以指定當A手勢發生時,即便A已經滿足條件了,也不會立刻觸發,會等到指定的手勢B確定失敗之後才觸發。
//添加雙擊手勢確定監測失敗才會觸發單擊手勢的相應操作
[tapOne requireGestureRecognizerToFail:tapTow];
如果手勢和scrollview一起使用就要防止只相應scrollView事件
scrollView.canCancelContentTouches=NO;
scrollView.delaysContentTouches=NO;
手勢的幾種狀態
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {
// 尚未識別是何種手勢操作(但可能已經觸發了觸摸事件),默認狀態
UIGestureRecognizerStatePossible,
// 手勢已經開始,此時已經被識別,但是這個過程中可能發生變化,手勢操作尚未完成
UIGestureRecognizerStateBegan,
// 手勢狀態發生轉變
UIGestureRecognizerStateChanged,
// 手勢識別操作完成(此時已經松開手指)
UIGestureRecognizerStateEnded,
// 手勢被取消,恢復到默認狀態
UIGestureRecognizerStateCancelled,
// 手勢識別失敗,恢復到默認狀態
UIGestureRecognizerStateFailed,
// 手勢識別完成,同UIGestureRecognizerStateEnded
UIGestureRecognizerStateRecognized
UIGestureRecognizerStateEnded
};
手勢經常用的屬性
//設置代理,具體的協議後面會說
@property(nullable,nonatomic,weak) id delegate;
//設置手勢是否有效
@property(nonatomic, getter=isEnabled) BOOL enabled;
//獲取手勢所在的view
@property(nullable, nonatomic,readonly) UIView *view;
//獲取觸發觸摸的點
-(CGPoint)locationInView:(nullable UIView*)view;
//設置觸摸點數
-(NSUInteger)numberOfTouches;
//獲取某一個觸摸點的觸摸位置
-(CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view;
//這個方法中第一個參數是需要時效的手勢,第二個是生效的手勢。
-(void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
//獲取到的是手指移動後,在相對坐標中的偏移量
-(CGPoint)translationInView:(nullable UIView *)view;
相對重要的BOOL屬性
@property(nonatomic) BOOL cancelsTouchesInView;
當這個屬性設置為YES時,如果識別到了手勢,
系統將會發送touchesCancelled:withEvent:消息在其時間傳遞鏈上,
終止觸摸事件的傳遞,
設置為NO,則不會終止事件的傳遞
@property(nonatomic) BOOL delaysTouchesBegan;
這個屬性設置手勢識別結束後,是立刻發送touchesEnded消息到事件傳遞鏈或者等待一個很短的時間後,
如果沒有接收到新的手勢識別任務,再發送。
UIGestureRecognizerDelegate
前面我們提到過關於手勢對象的協議代理,通過代理的回調,我們可以進行自定義手勢,也可以處理一些復雜的手勢關系,其中方法如下:
//手指觸摸屏幕後回調的方法,返回NO則不再進行手勢識別,方法觸發等
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
//開始進行手勢識別時調用的方法,返回NO則結束,不再觸發手勢
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
//是否支持多時候觸發,返回YES,則可以多個手勢一起觸發方法,返回NO則為互斥
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
//下面這個兩個方法也是用來控制手勢的互斥執行的
//這個方法返回YES,第一個手勢和第二個互斥時,第一個會失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);
//這個方法返回YES,第一個和第二個互斥時,第二個會失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);
UIGestureRecognizer的子類介紹
一、UITapGestureRecognizer(tap點按)
點擊作為最常用手勢,用於按下或選擇一個控件或條目(類似於普通的鼠標點擊); tap手勢屬於離散型手勢,特點是:一旦識別就無法取消,而且只會調用一次手勢操作事件(初始化手勢時指定的回調方法)
代碼
//一次點擊
UITapGestureRecognizer *tapOne = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapWithOne:)];
tapOne.delegate = self;
[self.view addGestureRecognizer:tapOne];
//設置觸控對象的個數(幾個手指)
[tapOne setNumberOfTouchesRequired:1];
//點擊次數
[tapOne setNumberOfTapsRequired:1];
//兩次點擊
UITapGestureRecognizer *tapTow = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapWithTow:)];
tapTow.delegate = self;
//一根手指操作
[tapOne setNumberOfTouchesRequired:1];
//點擊兩次生效
tapTow.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:tapTow];
//添加雙擊手勢確定監測失敗才會觸發單擊手勢的相應操作
[tapOne requireGestureRecognizerToFail:tapTow];
```
-(void)tapWithOne: (UITapGestureRecognizer *)tapOne {
NSLog(@”被點擊了一次”);
}
-(void)tapWithTow: (UITapGestureRecognizer *)tapTow {
NSLog(@”被點擊了兩次”);
}
---
**二、 長按手勢 UILongPressGestureRecognizer**
1.屬性:
//長點擊響應前點擊次數,默認0;
@property (nonatomic) NSUInteger numberOfTapsRequired;
//__TVOS_PROHIBITED: 用戶觸摸的手指數,默認1;
@property (nonatomic) NSUInteger numberOfTouchesRequired ;
//長按最低時間,默認0.5秒;
@property (nonatomic) CFTimeInterval minimumPressDuration;
// 手指長按期間可移動的區域,默認10像素。
@property (nonatomic) CGFloat allowableMovement;
---
**三、捏合手勢 UIPinchGestureRecognizer**
1.屬性:
//縮放的比例,默認為1;
@property (nonatomic) CGFloat scale;
//縮放的速度,放大為+,縮小為-。
@property (nonatomic,readonly) CGFloat velocity;
“`