UIGestureRecognizer手勢識別器

經過touches方法監聽view觸摸事件,有很明顯的幾個缺點ui

必須得自定義viewatom

因爲是在view內部的touches方法中監聽觸摸事件,所以默認狀況下,沒法讓其餘外界對象監聽view的觸摸事件spa

不容易區分用戶的具體手勢行爲代理

iOS3.2後,蘋果推出了手勢識別功能(GestureRecognizer,在觸摸事件處理方面,大大簡化了開發者的開發難度code

 

UIGestureRecognizer是一個抽象類,定義了全部手勢的基本行爲,使用它的子類才能處理具體的手勢orm

UITapGestureRecognizer(敲擊)對象

UIPinchGestureRecognizer(捏合,用於縮放)事件

UIPanGestureRecognizer(拖拽)圖片

UISwipeGestureRecognizer(輕掃)ip

UIRotationGestureRecognizer(旋轉)

UILongPressGestureRecognizer(長按)

UIGestureRecognizer.h文件中的屬性與方法:

typedef NS_ENUM(NSInteger,UIGestureRecognizerState) {
    UIGestureRecognizerStatePossible,   // 還沒有識別是何種手勢操做(但可能已經觸發了觸摸事件),默認狀態
    UIGestureRecognizerStateBegan,      // 手勢已經開始,此時已經被識別,可是這個過程當中可能發生變化,手勢操做還沒有完成
    UIGestureRecognizerStateChanged,    // 手勢狀態發生轉變
    UIGestureRecognizerStateEnded,      // 手勢識別操做完成(此時已經鬆開手指)
    UIGestureRecognizerStateCancelled,  // 手勢被取消,恢復到默認狀態
    UIGestureRecognizerStateFailed,     // 手勢識別失敗,恢復到默認狀態
    UIGestureRecognizerStateRecognized =UIGestureRecognizerStateEnded // 識手勢識別完成,同UIGestureRecognizerStateEnded
};

// 獲取當前手勢狀態
@property(nonatomic,readonly) UIGestureRecognizerState state;  
@property(nullable,nonatomic,weak) id <UIGestureRecognizerDelegate> delegate; 
// 手勢識別是否可用
@property(nonatomic, getter=isEnabled) BOOL enabled;  
// 獲取手勢觸摸的View視圖
@property(nullable, nonatomic,readonly) UIView *view;

/* 是否取消觸摸控件的響應
默認爲YES,這種狀況下當手勢識別器識別到觸摸以後,會發送touchesCancelled給觸摸到的控件以取消控件view對touch的響應,這個時候只有手勢識別器響應touch,當設置成NO時,手勢識別器識別到觸摸以後不會發送touchesCancelled給控件,這個時候手勢識別器和控件view均響應touch。
注意:手勢識別和觸摸事件是同時存在的,只是由於touchesCancelled致使觸摸事件失效 */
@property(nonatomic) BOOL cancelsTouchesInView;       

/* 是否延遲發送觸摸事件給觸摸到的控件
默認是NO,這種狀況下當發生一個觸摸時,手勢識別器先捕捉到到觸摸,而後發給觸摸到的控件,二者各自作出響應。若是設置爲YES,手勢識別器在識別的過程當中(注意是識別過程),不會將觸摸發給觸摸到的控件,即控件不會有任何觸摸事件。只有在識別失敗以後纔會將觸摸事件發給觸摸到的控件,這種狀況下控件view的響應會延遲約0.15ms。*/
@property(nonatomic) BOOL delaysTouchesBegan;         

/* 若是觸摸識別失敗是否當即結束本次手勢識別的觸摸事件(讓觸摸控件去識別觸摸事件)
默認爲YES,這種狀況下發生一個觸摸時,在手勢識別成功後,發送給touchesCancelled消息給觸摸控件view,手勢識別失敗時,會延遲大概0.15ms,期間沒有接收到別的觸摸纔會發送touchesEnded觸摸結束方法,若是設置爲NO,則不會延遲,即會當即發送touchesEnded以結束當前觸摸。*/
@property(nonatomic) BOOL delaysTouchesEnded;         

@property(nonatomic, copy) NSArray<NSNumber *> *allowedTouchTypes NS_AVAILABLE_IOS(9_0); 
@property(nonatomic, copy) NSArray<NSNumber *> *allowedPressTypes NS_AVAILABLE_IOS(9_0); 
// 觸摸手指數
@property(nonatomic, readonly) NSUInteger numberOfTouches;

// 建立一個手勢對象並添加觸發事件
- (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action NS_DESIGNATED_INITIALIZER; 
// 給一個手勢對象添加監聽事件
- (void)addTarget:(id)target action:(SEL)action;    
// 移除一個手勢的監聽事件
- (void)removeTarget:(nullable id)target action:(nullable SEL)action; 
/* 指定一個手勢須要另外一個手勢執行失敗纔會執行,同時觸發多個手勢使用其中一個手勢的解決辦法
有時手勢是相關聯的,如單機和雙擊,點擊和長按,點下去瞬間可能只會識別到單擊沒法識別其餘,該方法能夠指定某一個 手勢,即使本身已經知足條件了,也不會馬上觸發,會等到該指定的手勢肯定失敗以後才觸發*/
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
// 獲取當前觸摸在指定視圖上的點
- (CGPoint)locationInView:(nullable UIView*)view;                                
// 獲取觸摸手指數                                          
- (NSUInteger)numberOfTouches;
// 多指觸摸的觸摸點相對於指定視圖的位置                                         
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view;

/**************************  代理方法 ****************************/
// 開始進行手勢識別時調用的方法,返回NO則結束識別,再也不觸發手勢,用處:能夠在控件指定的位置使用手勢識別
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
/* 手指觸摸屏幕後回調的方法,返回NO則再也不進行手勢識別,方法觸發等
此方法在window對象在有觸摸事件發生時,調用gesture recognizer的touchesBegan:withEvent:方法以前調用,若是返回NO,則gesture recognizer不會看到此觸摸事件。(默認狀況下爲YES)*/
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;

// 手指按壓屏幕後回調的方法,返回NO則再也不進行手勢識別,方法觸發等
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press;

/* 是否支持多手勢觸發,返回YES,則能夠多個手勢一塊兒觸發方法,返回NO則爲互斥
是否容許多個手勢識別器共同識別,一個控件的手勢識別後是否阻斷手勢識別繼續向下傳播,默認返回NO;若是爲YES,響應者鏈上層對象觸發手勢識別後,若是下層對象也添加了手勢併成功識別也會繼續執行,不然上層對象識別後則再也不繼續傳播 */
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
// 下面這個兩個方法也是用來控制手勢的互斥執行的
//(1) 這個方法返回YES,第一個手勢和第二個互斥時,第一個會失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
//(2) 這個方法返回YES,第一個和第二個互斥時,第二個會失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

敲擊手勢:

 

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 一、建立一個敲擊手勢
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init];
    
    // 二、設置手勢對象的屬性
    // 點擊次數
    tapGesture.numberOfTapsRequired = 1;
    
    // 手指的數量
//    tapGesture.numberOfTouchesRequired = 2;
    
    // 設置代理
    tapGesture.delegate = self;
    
    // 三、把手勢添加到view上
    [self.view addGestureRecognizer:tapGesture];
    
    // 四、設置手勢的監聽方法
    [tapGesture addTarget:self action:@selector(tapView:)];

}

- (void)tapView:(UITapGestureRecognizer *)tapGest{
    NSLog(@"敲擊手勢的監聽方法");
}


長按手勢:

 

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 一、建立一個 「長按手勢」 對象
    UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] init];
    
    // 二、設置屬性
    // 長按最少持續多長時間
    longGesture.minimumPressDuration = 2;
    // 長按時,距離 「觸摸點」 可移動的距離
    longGesture.allowableMovement = 30;
    
    // 三、把手勢添加到view上
    [self.imageView addGestureRecognizer:longGesture];
    
    // 四、設置手勢的監聽方法
    [longGesture addTarget:self action:@selector(longPressView:)];

}

- (void)longPressView:(UILongPressGestureRecognizer *)longPressGesture{
    // 怎麼判斷長按開始和結束
    // 經過手勢的狀態來判斷
    if (longPressGesture.state == UIGestureRecognizerStateBegan) {
        NSLog(@"長按手勢開始");
    }else{
        NSLog(@"長按手勢結束");
    }
}


輕掃手勢:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 一、建立一個 「輕掃手勢」 對象
    UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeView:)];
    
    // 二、設置屬性
    //UISwipeGestureRecognizerDirectionRight 向右輕掃
    //UISwipeGestureRecognizerDirectionLeft    向左輕掃
    //UISwipeGestureRecognizerDirectionUp    向上
    //UISwipeGestureRecognizerDirectionDown 向下
    
    swipeGesture.direction = UISwipeGestureRecognizerDirectionDown;
    
    // 三、把手勢添加到view上
    [self.imageView addGestureRecognizer:swipeGesture];
}

- (void)swipeView:(UIGestureRecognizer *)swipeGest{
    // 怎麼判斷 "長按" 開始和結束
    NSLog(@"%s 手勢狀態 %ld",__func__, swipeGest.state);
}


捏合手勢:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 一、建立一個 「捏合手勢」 對象
    UIPinchGestureRecognizer *pinchGest = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinView:)];
    
    // 二、把手勢添加到 view上
    [self.imageView addGestureRecognizer:pinchGest];
    
}

- (void)pinView:(UIPinchGestureRecognizer *)pinGest{
    
    // 縮放的比例是一個 「累加」 的過程
#warning 放大圖片後,再次縮放的時候,立刻回到原先的大小
//    self.imageView.transform = CGAffineTransformMakeScale(pinGest.scale, pinGest.scale);
    
    self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinGest.scale, pinGest.scale);
    
    // 讓比例還原 ,不累加
    // 解決辦法
    pinGest.scale = 1;
}


旋轉手勢:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 一、添加一個 「旋轉手勢」 對像
    UIRotationGestureRecognizer *rotationGest = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationView:)];
    
    // 二、把手勢添加到 view上
    [self.imageView addGestureRecognizer:rotationGest];
}

- (void)rotationView:(UIRotationGestureRecognizer *)rotationGesture{
    
    // 旋轉角度
    // 旋轉角度也是一個累加過程
    // 設置圖片的旋轉
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotationGesture.rotation);
    
    // 清除 「旋轉角度」 的累加
    rotationGesture.rotation = 0;
}

 

旋轉、捏合手勢:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 默認狀況下,控件只能監聽到一種手勢
    // 若是要監聽到多個手勢,設置一個代理的方法,告知它容許 「多個手勢」 並存
    
    // 給圖片添加一個 「旋轉手勢」 對象
    // 一、建立一個  「旋轉手勢」 對象
    UIRotationGestureRecognizer *rotationGest = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationView:)];
    
    // 設置代理
    rotationGest.delegate = self;
    
    // 二、把手勢添加到 view上
    [self.view addGestureRecognizer:rotationGest];
    
    // 三、給圖片添加 「捏合手勢」
    UIPinchGestureRecognizer *pinchGest = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)];
    [self.imageView addGestureRecognizer:pinchGest];
    
    
}

- (void)rotationView:(UIRotationGestureRecognizer *)rotationGesture{
    
    // 旋轉角度
    // 旋轉角度也是一個累加過程
    // 設置圖片的旋轉
    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotationGesture.rotation);
    
    // 清除 「旋轉角度」 的累加
    rotationGesture.rotation = 0;
}
- (void)pinchView:(UIPinchGestureRecognizer *)pinGest{
    
    // 縮放的比例是一個 「累加」 的過程
#warning 放大圖片後,再次縮放的時候,立刻回到原先的大小
//    self.imageView.transform = CGAffineTransformMakeScale(pinGest.scale, pinGest.scale);
    
    self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinGest.scale, pinGest.scale);
    
    // 讓比例還原 ,不累加
    // 解決辦法
    pinGest.scale = 1;
}


// simultaneous  同時發生
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    
    return YES;
}


拖拽手勢:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 給圖片添加 「拖拽手勢」
    // 一、建立一個 「拖拽手勢」 對象
    UIPanGestureRecognizer *panGest = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panView:)];
    // 二、添加到view
    [self.imageView addGestureRecognizer:panGest];
}

- (void)panView:(UIPanGestureRecognizer *)panGest{
    
    // panGest.view 觸摸的view
    // 拖拽的距離 (距離是一個累加的過程)
    CGPoint trans = [panGest translationInView:panGest.view];
    
    // 設置圖片移動
    CGPoint center = self.imageView.center;
    center.x += trans.x;
    center.y += trans.y;
    self.imageView.center = center;
    
    // 清除累加的距離
    [panGest setTranslation:CGPointZero inView:panGest.view];
}


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

storyboard建立手勢:

一、選取對應的手勢

二、拖到要添加手勢的控件上

三、連線

其餘手勢方法同上

相關文章
相關標籤/搜索