經過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建立手勢:
一、選取對應的手勢
二、拖到要添加手勢的控件上
三、連線
其餘手勢方法同上