iOS手势UIGestureRecognizer的使用及手势冲突的解决办法【转】
iOS手勢UIGestureRecognizer的使用及手勢沖突的解決辦法【轉(zhuǎn)】
轉(zhuǎn)自:iOS開發(fā)中的手勢體系——UIGestureRecognizer分析及其子類的使用
關(guān)于手勢的一篇很好的帖子,轉(zhuǎn)載過來免得丟失。你可能最感興趣的是手勢間的互斥處理,那么就搜索?4、手勢間的互斥處理。
一、引言
????????在iOS系統(tǒng)中,手勢是進(jìn)行用戶交互的重要方式,通過UIGestureRecognizer類,我們可以輕松的創(chuàng)建出各種手勢應(yīng)用于app中。關(guān)于UIGestureRecognizer類,是對iOS中的事件傳遞機(jī)制面向應(yīng)用的封裝,將手勢消息的傳遞抽象為了對象。有關(guān)消息傳遞的一些討論,在前面的博客中有提到:
iOS事件響應(yīng)控制:http://my.oschina.net/u/2340880/blog/396161。
二、手勢的抽象類——UIGestureRecognizer
????????UIGestureRecognizer將一些和手勢操作相關(guān)的方法抽象了出來,但它本身并不實(shí)現(xiàn)什么手勢,因此,在開發(fā)中,我們一般不會直接使用UIGestureRecognizer的對象,而是通過其子類進(jìn)行實(shí)例化,iOS系統(tǒng)給我們提供了許多用于我們實(shí)例的子類,這些我們后面再說,我們先來看一下,UIGestureRecognizer中抽象出了哪些方法。
1、統(tǒng)一的初始化方法
????????UIGestureRecognizer類為其子類準(zhǔn)備好了一個(gè)統(tǒng)一的初始化方法,無論什么樣的手勢動作,其執(zhí)行的結(jié)果都是一樣的:觸發(fā)一個(gè)方法,可以使用下面的方法進(jìn)行統(tǒng)一的初始化:
- (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action;當(dāng)然,如果我們使用alloc-init的方式,也是可以的,下面的方法可以為手勢添加觸發(fā)的selector:
- (void)addTarget:(id)target action:(SEL)action;與之相對應(yīng)的,我們也可以將一個(gè)selector從其手勢對象上移除:
- (void)removeTarget:(nullable id)target action:(nullable SEL)action;上面兩個(gè)方法是十分有意思的,因?yàn)閍ddTarget方式的存在,iOS系統(tǒng)允許一個(gè)手勢對象可以添加多個(gè)selector觸發(fā)方法,并且觸發(fā)的時(shí)候,所有添加的selector都會被執(zhí)行,我們以點(diǎn)擊手勢示例如下:
- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.UITapGestureRecognizer * ges = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(click:)];[ges addTarget:self action:@selector(haha)];[self.view addGestureRecognizer:ges]; } -(void)click:(UIGestureRecognizer *)ges{NSLog(@"第一個(gè)手勢的觸發(fā)方法");} -(void)haha{NSLog(@"haha"); }運(yùn)行后點(diǎn)擊屏幕,打印如下,說明兩個(gè)方法都觸發(fā)了:
2、手勢狀態(tài)
? ?UIgestureRecognizer類中有如下一個(gè)屬性,里面枚舉了一些手勢的當(dāng)前狀態(tài):
@property(nonatomic,readonly) UIGestureRecognizerState state;枚舉值如下:
typedef NS_ENUM(NSInteger, UIGestureRecognizerState) {UIGestureRecognizerStatePossible, // 默認(rèn)的狀態(tài),這個(gè)時(shí)候的手勢并沒有具體的情形狀態(tài)UIGestureRecognizerStateBegan, // 手勢開始被識別的狀態(tài)UIGestureRecognizerStateChanged, // 手勢識別發(fā)生改變的狀態(tài)UIGestureRecognizerStateEnded, // 手勢識別結(jié)束,將會執(zhí)行觸發(fā)的方法UIGestureRecognizerStateCancelled, // 手勢識別取消UIGestureRecognizerStateFailed, // 識別失敗,方法將不會被調(diào)用UIGestureRecognizerStateRecognized = UIGestureRecognizerStateEnded };3、常用屬性和方法
//設(shè)置代理,具體的協(xié)議后面會說 @property(nullable,nonatomic,weak) id <UIGestureRecognizerDelegate> delegate; //設(shè)置手勢是否有效 @property(nonatomic, getter=isEnabled) BOOL enabled; //獲取手勢所在的view @property(nullable, nonatomic,readonly) UIView *view; //獲取觸發(fā)觸摸的點(diǎn) - (CGPoint)locationInView:(nullable UIView*)view; //設(shè)置觸摸點(diǎn)數(shù) - (NSUInteger)numberOfTouches; //獲取某一個(gè)觸摸點(diǎn)的觸摸位置 - (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view;下面的幾個(gè)BOOL值的屬性,對于手勢觸發(fā)的控制也十分重要:
(1)
@property(nonatomic) BOOL cancelsTouchesInView;上面的屬性默認(rèn)為YES,當(dāng)這個(gè)屬性設(shè)置為YES時(shí),如果識別到了手勢,系統(tǒng)將會發(fā)送touchesCancelled:withEvent:消息在其時(shí)間傳遞鏈上,終止觸摸事件的傳遞,設(shè)置為NO,則不會終止事件的傳遞,舉個(gè)例子來說,可能會更加清楚一些如下:
- (void)viewDidLoad {[super viewDidLoad];UIPanGestureRecognizer * ges = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(click:)];;[self.view addGestureRecognizer:ges];ges.cancelsTouchesInView=NO; } -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSLog(@"123"); } -(void)click:(UIGestureRecognizer *)ges{NSLog(@"第一個(gè)手勢的觸發(fā)方法"); }上面我們使用了拖拽手勢和touchesMoved兩個(gè)觸發(fā)方式,當(dāng)我們把cancelTouchesInView設(shè)置為NO時(shí),在屏幕上滑動,會發(fā)現(xiàn)兩種方式都在觸發(fā),打印如下:
如果我們將cancelTouchesInView改為YES,當(dāng)手勢觸發(fā)時(shí),將取消觸摸消息的觸發(fā):
(2)
@property(nonatomic) BOOL delaysTouchesBegan;通過上面的例子,我們知道,在一個(gè)手勢觸發(fā)之前,是會一并發(fā)消息給事件傳遞鏈的,delaysTouchesBgan屬性用于控制這個(gè)消息的傳遞時(shí)機(jī),默認(rèn)這個(gè)屬性為NO,此時(shí)在觸摸開始的時(shí)候,就會發(fā)消息給事件傳遞鏈,如果我們設(shè)置為YES,在觸摸沒有被識別失敗前,都不會給事件傳遞鏈發(fā)送消息。
(3)
@property(nonatomic) BOOL delaysTouchesEnded;這個(gè)屬性設(shè)置手勢識別結(jié)束后,是立刻發(fā)送touchesEnded消息到事件傳遞鏈或者等待一個(gè)很短的時(shí)間后,如果沒有接收到新的手勢識別任務(wù),再發(fā)送。
4、手勢間的互斥處理
????????有一點(diǎn)需要注意,同一個(gè)View上是可以添加多個(gè)手勢對象的,默認(rèn)這個(gè)手勢是互斥的,一個(gè)手勢觸發(fā)了就會默認(rèn)屏蔽其他相似的手勢動作,例如:
- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.UITapGestureRecognizer * ges = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(click:)];;//view.backgroundColor = [UIColor redColor];//ges.delegate=self;[self.view addGestureRecognizer:ges];UITapGestureRecognizer * ges2 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(click1:)]; // ges2.delegate=self;[self.view addGestureRecognizer:ges2]; }-(void)click:(UIGestureRecognizer *)ges{NSLog(@"第一個(gè)手勢的觸發(fā)方法");} -(void)click1:(UIGestureRecognizer *)ges1{NSLog(@"第二個(gè)手勢的觸發(fā)方法");}我們添加的兩個(gè)手勢都是單機(jī)手勢,會產(chǎn)生沖突,觸發(fā)是很隨機(jī)的,如果我們想設(shè)置一下當(dāng)手勢互斥時(shí)要優(yōu)先觸發(fā)的手勢,可以使用如下的方法:
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;這個(gè)方法中第一個(gè)參數(shù)是需要失效的手勢,第二個(gè)是生效的手勢。
三、UIGestureRecognizerDelegate
????????前面我們提到過關(guān)于手勢對象的協(xié)議代理,通過代理的回調(diào),我們可以進(jìn)行自定義手勢,也可以處理一些復(fù)雜的手勢關(guān)系,其中方法如下:
//手指觸摸屏幕后回調(diào)的方法,返回NO則不再進(jìn)行手勢識別,方法觸發(fā)等 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch; //開始進(jìn)行手勢識別時(shí)調(diào)用的方法,返回NO則結(jié)束,不再觸發(fā)手勢 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer; //是否支持多時(shí)候觸發(fā),返回YES,則可以多個(gè)手勢一起觸發(fā)方法,返回NO則為互斥 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer; //下面這個(gè)兩個(gè)方法也是用來控制手勢的互斥執(zhí)行的 //這個(gè)方法返回YES,第一個(gè)手勢和第二個(gè)互斥時(shí),第一個(gè)會失效 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0); //這個(gè)方法返回YES,第一個(gè)和第二個(gè)互斥時(shí),第二個(gè)會失效 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);四、點(diǎn)擊手勢——UITapGestureRecognizer
????????點(diǎn)擊手勢十分簡單,支持單擊和多次點(diǎn)擊,在我們手指觸摸屏幕并抬起手指時(shí)會進(jìn)行觸發(fā),其中有如下兩個(gè)屬性我們可以進(jìn)行設(shè)置:
//設(shè)置點(diǎn)擊次數(shù),默認(rèn)為單擊 @property (nonatomic) NSUInteger numberOfTapsRequired; //設(shè)置同時(shí)點(diǎn)擊的手指數(shù) @property (nonatomic) NSUInteger numberOfTouchesRequired;五、捏合手勢——UIPinchGestureRecognizer
????????捏合手勢是當(dāng)我們雙指捏合和擴(kuò)張會觸發(fā)動作的手勢,我們可以設(shè)置的屬性如下:
//設(shè)置縮放比例 @property (nonatomic) CGFloat scale; //設(shè)置捏合速度 @property (nonatomic,readonly) CGFloat velocity;六、拖拽手勢——UIPanGestureRecognzer
? ?當(dāng)我們點(diǎn)中視圖進(jìn)行慢速拖拽時(shí)會觸發(fā)拖拽手勢的方法。
//設(shè)置觸發(fā)拖拽的最少觸摸點(diǎn),默認(rèn)為1 @property (nonatomic) NSUInteger minimumNumberOfTouches; //設(shè)置觸發(fā)拖拽的最多觸摸點(diǎn) @property (nonatomic) NSUInteger maximumNumberOfTouches; //獲取當(dāng)前位置 - (CGPoint)translationInView:(nullable UIView *)view; //設(shè)置當(dāng)前位置 - (void)setTranslation:(CGPoint)translation inView:(nullable UIView *)view; //設(shè)置拖拽速度 - (CGPoint)velocityInView:(nullable UIView *)view;七、滑動手勢——UISwipeGestureRecognizer
????????滑動手勢和拖拽手勢的不同之處在于滑動手勢更快,拖拽比較慢。
//設(shè)置觸發(fā)滑動手勢的觸摸點(diǎn)數(shù) @property(nonatomic) NSUInteger numberOfTouchesRequired; //設(shè)置滑動方向 @property(nonatomic) UISwipeGestureRecognizerDirection direction; //枚舉如下 typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) {UISwipeGestureRecognizerDirectionRight = 1 << 0,UISwipeGestureRecognizerDirectionLeft = 1 << 1,UISwipeGestureRecognizerDirectionUp = 1 << 2,UISwipeGestureRecognizerDirectionDown = 1 << 3 };八、旋轉(zhuǎn)手勢——UIRotationGestureRecognizer
????????進(jìn)行旋轉(zhuǎn)動作時(shí)觸發(fā)手勢方法。
//設(shè)置旋轉(zhuǎn)角度 @property (nonatomic) CGFloat rotation; //設(shè)置旋轉(zhuǎn)速度 @property (nonatomic,readonly) CGFloat velocity;九、長按手勢——UILongPressGestureRecognizer
進(jìn)行長按的時(shí)候觸發(fā)的手勢方法。 //設(shè)置觸發(fā)前的點(diǎn)擊次數(shù) @property (nonatomic) NSUInteger numberOfTapsRequired; //設(shè)置觸發(fā)的觸摸點(diǎn)數(shù) @property (nonatomic) NSUInteger numberOfTouchesRequired; //設(shè)置最短的長按時(shí)間 @property (nonatomic) CFTimeInterval minimumPressDuration; //設(shè)置在按觸時(shí)時(shí)允許移動的最大距離 默認(rèn)為10像素 @property (nonatomic) CGFloat allowableMovement;?
?
總結(jié)
以上是生活随笔為你收集整理的iOS手势UIGestureRecognizer的使用及手势冲突的解决办法【转】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

- 上一篇: MTK笔试1题~
- 下一篇: 海康威视摄像头+OpenCV+VS201