你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS之UIGestureRecognier手勢詳解

iOS之UIGestureRecognier手勢詳解

編輯:IOS開發綜合

一.手勢UIGestureRecognier簡介

iOS 3.2之後,蘋果推出了手勢識別功能(Gesture Recognizer),在觸摸事件處理方面,大大簡化了開發者的開發難度。利用UIGestureRecognizer,能輕松識別用戶在某個view上面做的一些常見手勢。UIGestureRecognizer是一個抽象類,對iOS中的事件傳遞機制面向應用進行封裝,將手勢消息的傳遞抽象為了對象。其中定義了所有手勢的基本行為,使用它的子類才能處理具體的手勢。

二.手勢的抽象類——UIGestureRecognizer

UIGestureRecognizer將一些和手勢操作相關的方法抽象了出來,但它本身並不實現什麼手勢,因此,在開發中,我們一般不會直接使用UIGestureRecognizer的對象,而是通過其子類進行實例化,iOS系統給我們提供了許多用於實例的子類,這些我們後面再說,我們先來看一下,UIGestureRecognizer中抽象出了哪些方法。

1.初始化方法

UIGestureRecognizer類為其子類准備好了一個統一的初始化方法,無論什麼樣的手勢動作,其執行的結果都是一樣的:觸發一個方法,可以使用下面的方法進行統一的初始化:

-(instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action

當然,如果我們使用alloc-init的方式,也是可以的,下面的方法可以為手勢添加觸發的selector:

-(void)addTarget:(id)target action:(SEL)action;

與之相對應的,我們也可以將一個selector從其手勢對象上移除:

-(void)removeTarget:(nullable id)target action:(nullable SEL)action;

因為addTarget方式的存在,iOS系統允許一個手勢對象可以添加多個selector觸發方法,並且觸發的時候,所有添加的selector都會被執行,我們以點擊手勢示例如下:

-(void)viewDidLoad{

  [super viewDidLoad];

  UITapGestureRecognizer*tap1=[[UITapGestureRecognizer alloc]initWithTarget:self action: selector(tap1:)];

  [tap1 addTarget:self action: selector(tap2:)];

  [self.view addGestureRecognizer:tap1];

  }

  -(void)tap1:(UITapGestureRecognizer*)tap

  {

  NSLog( "%s",__func__);

  }

  -(void)tap2:(UITapGestureRecognizer*)tap

  {

  NSLog( "%s",__func__);

  }

點擊屏幕,打印內容如下,說明兩個方法都觸發了

這裡寫圖片描述

2.手勢狀態

UIgestureRecognizer類中有如下一個屬性,裡面枚舉了一些手勢的當前狀態:

 property(nonatomic,readonly)UIGestureRecognizerState state;

枚舉值如下:

typedef NS_ENUM(NSInteger,UIGestureRecognizerState){

  UIGestureRecognizerStatePossible,//默認的狀態,這個時候的手勢並沒有具體的情形狀態

  UIGestureRecognizerStateBegan,//手勢開始被識別的狀態

  UIGestureRecognizerStateChanged,//手勢識別發生改變的狀態

  UIGestureRecognizerStateEnded,//手勢識別結束,將會執行觸發的方法

  UIGestureRecognizerStateCancelled,//手勢識別取消

  UIGestureRecognizerStateFailed,//識別失敗,方法將不會被調用

  UIGestureRecognizerStateRecognized=UIGestureRecognizerStateEnded

  };

3.常用屬性和方法

    //手勢代理代理中有一些手勢觸發的方法,後面拿出來詳細說明

   property(nullable,nonatomic,weak)iddelegate;

  //設置手勢是否有效

   property(nonatomic,getter=isEnabled)BOOL enabled;

  //獲取手勢所在的View

   property(nullable,nonatomic,readonly)UIView*view;

  //默認是YES。當識別到手勢的時候,終止touchesCancelled:withEvent:或pressesCancelled:withEvent:發送的所有觸摸事件。

   property(nonatomic)BOOL cancelsTouchesInView;

  //默認為NO,在觸摸開始的時候,就會發消息給事件傳遞鏈,如果設置為YES,在觸摸沒有被識別失敗前,都不會給事件傳遞鏈發送消息。

   property(nonatomic)BOOL delaysTouchesBegan;

  //默認為YES。這個屬性設置手勢識別結束後,是立刻發送touchesEnded或pressesEnded消息到事件傳遞鏈或者等待一個很短的時間後,如果沒有接收到新的手勢識別任務,再發送。

   property(nonatomic)BOOL delaysTouchesEnded;

   property(nonatomic,copy)NSArray*allowedTouchTypes NS_AVAILABLE_IOS(9_0);//Array of UITouchType's as NSNumbers.

   property(nonatomic,copy)NSArray*allowedPressTypes NS_AVAILABLE_IOS(9_0);//Array of UIPressTypes as NSNumbers.

  //[A requireGestureRecognizerToFail:B]手勢互斥它可以指定當A手勢發生時,即便A已經滿足條件了,也不會立刻觸發,會等到指定的手勢B確定失敗之後才觸發。

  -(void)requireGestureRecognizerToFail:(UIGestureRecognizer*)otherGestureRecognizer;

  //獲取當前觸摸的點

  -(CGPoint)locationInView:(nullable UIView*)view;

  //設置觸摸點數

  -(NSUInteger)numberOfTouches;

  //獲取某一個觸摸點的觸摸位置

  -(CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view;

3.1個別屬性詳解

其中幾個BOOL值的屬性,對於手勢觸發的控制也十分重要,下面我們舉個栗子來詳細說明一下以下三個方法。

    property(nonatomic)BOOL cancelsTouchesInView;

   property(nonatomic)BOOL delaysTouchesBegan;

   property(nonatomic)BOOL delaysTouchesEnded;
-(void)viewDidLoad{

  [super viewDidLoad];

  UIPanGestureRecognizer*pan=[[UIPanGestureRecognizer alloc]initWithTarget:self action: selector(pan:)];

  pan.cancelsTouchesInView=NO;

  //pan.delaysTouchesBegan=YES;

  [self.view addGestureRecognizer:pan];

  }

  -(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event

  {

  NSLog( "touchMoved手勢觸發");

  }

  -(void)pan:(UIPanGestureRecognizer*)pan{

  NSLog( "pan手勢觸發");

  }

pan.cancelsTouchesInView屬性默認設置為YES,如果識別到了手勢,系統將會發送touchesCancelled:withEvent:消息在其時間傳遞鏈上,終止觸摸事件的傳遞,也就是說默認當識別到手勢時,touch事件傳遞的方法將被終止而不執行,如果設置為NO,touch事件傳遞的方法仍然會被執行,上例中我們使用了拖拽手勢和touchesMoved兩個觸發方式,當我們把cancelTouchesInView設置為NO時,在屏幕上滑動,兩種方式都在觸發,打印如下:

這裡寫圖片描述

而當我們將pan.cancelsTouchesInView = YES屬性設置為YES時,打印結果如下

這裡寫圖片描述

我們發現touchesMoved的方法仍然被調用了,這是為什麼呢?這就涉及到第二個屬性delaysTouchesBegan,這是因為手勢識別是有一個過程的,拖拽手勢需要一個很小的手指移動的過程才能被識別為拖拽手勢,而在一個手勢觸發之前,是會一並發消息給事件傳遞鏈的,所以才會有最開始的幾個touchMoved方法被調用,當識別出拖拽手勢以後,就會終止touch事件的傳遞。
delaysTouchesBgan屬性用於控制這個消息的傳遞時機,默認這個屬性為NO,此時在觸摸開始的時候,就會發消息給事件傳遞鏈,如果我們設置為YES,在觸摸沒有被識別失敗前,都不會給事件傳遞鏈發送消息。
因此當我們設置pan.delaysTouchesBegan = YES;時打印內容如下<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20161012/201610120919301097.png" title="\" />

因為此時在拖拽手勢識別失敗之前,都不會給時間傳遞鏈發送消息,所以就不會在調用touchesMoved觸發事件了

而delaysTouchesEnded屬性默認是YES,當設為YES時在手勢識別結束後,會等待一個很短的時間,如果沒有接收到新的手勢識別任務,才會發送touchesEnded消息到事件傳遞鏈,設置為NO之後會立刻發送touchesEnded消息到事件傳遞鏈我們同樣來看一個例子:

- (void)viewDidLoad {
    [super viewDidLoad];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
    tap.numberOfTapsRequired = 3;
// tap.cancelsTouchesInView = NO;
// tap.delaysTouchesBegan = YES;
    tap.delaysTouchesEnded = NO;
    [self.view addGestureRecognizer:tap];    
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"touchBegan手勢開始");
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchEnd手勢觸發結束");
}
-(void)tap:(UITapGestureRecognizer *)tap
{
    NSLog(@"tap手勢觸發");
}

當tap.delaysTouchesEnded = NO;時,輕拍三下屏幕,打印如下

這裡寫圖片描述

我們發現我們每點擊一下,都會立即發送touchesEnded消息到事件傳遞鏈。
而當tap.delaysTouchesEnded = YES;時,輕拍三下屏幕,打印如下

這裡寫圖片描述

等三下輕拍手勢識別結束後,才會發送消息到事件傳遞鏈。

3.2重點方法詳解-手勢間的互斥處理

同一個View上是可以添加多個手勢對象的,默認這些手勢是互斥的,一個手勢觸發了就會默認屏蔽其他相似的手勢動作。比如,單擊和雙擊並存時,如果不做處理,它就只能發送出單擊的消息。為了能夠識別出雙擊手勢,就需要用下面的方法一個特殊處理邏輯,即先判斷手勢是否是雙擊,在雙擊失效的情況下作為單擊手勢處理。

-(void)requireGestureRecognizerToFail:(UIGestureRecognizer*)otherGestureRecognizer;

[A requireGestureRecognizerToFail:B]它可以指定當A手勢發生時,即便A已經滿足條件了,也不會立刻觸發,會等到指定的手勢B確定失敗之後才觸發。

看一個例子

-(void)viewDidLoad{

  [super viewDidLoad];

  UITapGestureRecognizer*tap1=[[UITapGestureRecognizer alloc]initWithTarget:self action: selector(tap1:)];

  tap1.numberOfTapsRequired=1;

  [self.view addGestureRecognizer:tap1];

  UITapGestureRecognizer*tap2=[[UITapGestureRecognizer alloc]initWithTarget:self action: selector(tap2:)];

  tap2.numberOfTapsRequired=2;

  [self.view addGestureRecognizer:tap2];

  //當tap2手勢觸發失敗時才會觸發tap1手勢

  [tap1 requireGestureRecognizerToFail:tap2];

  }

  -(void)tap1:(UITapGestureRecognizer*)tap

  {

  NSLog( "tap1手勢觸發");

  }

  -(void)tap2:(UITapGestureRecognizer*)tap

  {

  NSLog( "tap2手勢觸發");

  }

3.3.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子類及子類屬性

除了UIGestureRecognizer中的方法和屬性是所有子類通用的之外,UIGestureRecognizer子類中分別有不同的屬性和方法來對應不同的手勢。

1.點擊手勢——UITapGestureRecognizer

點擊手勢十分簡單,支持單擊和多次點擊,在我們手指觸摸屏幕並抬起手指時會進行觸發,其中有如下兩個屬性我們可以進行設置:

    //設置點擊次數,默認為單擊

   property(nonatomic)NSUInteger numberOfTapsRequired;

  //設置同時點擊的手指數

   property(nonatomic)NSUInteger numberOfTouchesRequired;

2.捏合手勢——UIPinchGestureRecognizer

捏合手勢是當我們雙指捏合和擴張會觸發動作的手勢,我們可以設置的屬性如下:

    //設置縮放比例

   property(nonatomic)CGFloat scale;

  //設置捏合速度

   property(nonatomic,readonly)CGFloat velocity;

3.拖拽手勢——UIPanGestureRecognzer

當我們點中視圖進行慢速拖拽時會觸發拖拽手勢的方法。

    //設置觸發拖拽的最少觸摸點,默認為1

   property(nonatomic)NSUInteger minimumNumberOfTouches;

  //設置觸發拖拽的最多觸摸點

   property(nonatomic)NSUInteger maximumNumberOfTouches;

  //獲取當前位置

  -(CGPoint)translationInView:(nullable UIView*)view;

  //設置當前位置

  -(void)setTranslation:(CGPoint)translation inView:(nullable UIView*)view;

  //設置拖拽速度

  -(CGPoint)velocityInView:(nullable UIView*)view;

4.滑動手勢——UISwipeGestureRecognizer

滑動手勢和拖拽手勢的不同之處在於滑動手勢更快,而拖拽比較慢。

    //設置觸發滑動手勢的觸摸點數

   property(nonatomic)NSUInteger numberOfTouchesRequired;

  //設置滑動方向

   property(nonatomic)UISwipeGestureRecognizerDirection direction;
//枚舉如下

  typedef NS_OPTIONS(NSUInteger,UISwipeGestureRecognizerDirection){

  UISwipeGestureRecognizerDirectionRight=1<<0,

  UISwipeGestureRecognizerDirectionLeft=1<<1,

  UISwipeGestureRecognizerDirectionUp=1<<2,

  UISwipeGestureRecognizerDirectionDown=1<<3

  };

5.旋轉手勢——UIRotationGestureRecognizer

進行旋轉動作時觸發手勢方法。

    //設置旋轉角度

   property(nonatomic)CGFloat rotation;

  //設置旋轉速度

   property(nonatomic,readonly)CGFloat velocity;

6.長按手勢——UILongPressGestureRecognizer

進行長按的時候觸發的手勢方法。

    //設置觸發前的點擊次數

   property(nonatomic)NSUInteger numberOfTapsRequired;

  //設置觸發的觸摸點數

   property(nonatomic)NSUInteger numberOfTouchesRequired;

  //設置最短的長按時間

   property(nonatomic)CFTimeInterval minimumPressDuration;

  //設置在按觸時時允許移動的最大距離默認為10像素

   property(nonatomic)CGFloat allowableMovement;

7.自定義手勢

自定義手勢繼承:UIGestureRecognizer,實現下面的方法,在以下方法中判斷自定義手勢是否實現。

    –touchesBegan:withEvent:

  –touchesMoved:withEvent:

  –touchesEnded:withEvent:

  -touchesCancelled:withEvent:

注意.m文件中需要引入#import

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved