一、響應者鏈
以UIResponder作為超類的任何類都是響應者。UIView和UIControl是UIReponder的子類,因此所有視圖和所有控制項都是響應者。
1、初始相應器
事件首先會傳遞給UIApplication對象,接下來會傳遞給應用程式的UIWindow,UIWindow會選擇一個初始相應器來處理事件。初始響應器會選擇下面的方式選擇1、對於觸摸事件,UIWindow會確定使用者觸摸的視圖,然後將事件交給註冊了這個視圖的手勢辨識器或則註冊視圖層級更高的手勢辨識器。只要存在能處理事件的辨識器,就不會再繼續找了。如果沒有的話,被觸摸視圖就是初始相應器,事件也會傳遞給它。
2、對於使用者搖晃裝置產生的或者是來自遠程遙控裝置事件,將會傳遞給第一響應器
如果初始響應器不處理時間,它會將事件傳遞給它的父視圖(如果存在的話),或者傳遞給視圖控制器(如果此視圖是視圖控制器的視圖)。如果視圖控制器不處理事件,它將沿著響應器鏈的層級繼續傳給父視圖控制器(如果存在的話)。
如果在整個視圖層級中都沒與能處理事件的視圖或控制器,事件就會被傳遞給應用程式的視窗。如果視窗不能處理事件,而應用委託是UIResponder的子類,UIApplication對象就會將其傳遞給應用程式委託。最後,如果應用委託不是UIResponder的子類,或者不處理這個事件,那麼這個事件將會被丟棄。
4個手勢通知方法
#pragma mark - Touch Event Methods// 使用者第一次觸控螢幕幕時被調用- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{}// 當發生某些事件(如來電呼叫)導致手勢中斷時被調用- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{}// 當使用者手指離開螢幕時被調用- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{}// 當使用者手指移動時觸發- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{}
二、檢測掃描事件
1、手動檢測
//// ViewController.m// Swipes//// Created by Jierism on 16/8/4.// Copyright © 2016年 Jierism. All rights reserved.//#import "ViewController.h"// 設定檢測範圍static CGFloat const kMinimmGestureLength = 25;static CGFloat const kMaximmVariance = 5;@interface ViewController ()@property (weak, nonatomic) IBOutlet UILabel *label;@property (nonatomic) CGPoint gestureStartPoint;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; self.gestureStartPoint = [touch locationInView:self.view];}- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ UITouch *touch = [touches anyObject]; CGPoint currentPosition = [touch locationInView:self.view]; // 返回一個float的絕對值 CGFloat deltaX = fabsf(self.gestureStartPoint.x - currentPosition.x); CGFloat deltaY = fabsf(self.gestureStartPoint.y - currentPosition.y); // 獲得兩個增量後,判斷使用者在兩個方向上移動過的距離,檢測使用者是否在一個方向上移動得足夠遠但在另一個方向移動得不夠來形成輕掃動作 if (deltaX >= kMinimmGestureLength && deltaY <= kMaximmVariance) { self.label.text = @"Horizontal swipe detected"; // 2s後擦除文本 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.label.text = @""; }); }else if (deltaY >= kMinimmGestureLength && deltaX <= kMaximmVariance){ self.label.text = @"Vertical swipe detected"; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.label.text = @""; }); }}@end
2、辨識器檢測
//// ViewController.m// Swipes//// Created by Jierism on 16/8/4.// Copyright © 2016年 Jierism. All rights reserved.//#import "ViewController.h"@interface ViewController ()@property (weak, nonatomic) IBOutlet UILabel *label;@property (nonatomic) CGPoint gestureStartPoint;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //建立兩個手勢辨識器 // 1、水平方向辨識器 UISwipeGestureRecognizer *horizontal = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(reportHorizontalSwipe:)]; horizontal.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:horizontal]; // 2、垂直方向辨識器 UISwipeGestureRecognizer *vertical = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(reportVerticalSwipe:)]; vertical.direction = UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown; [self.view addGestureRecognizer:vertical];}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}- (void)reportHorizontalSwipe:(UIGestureRecognizer *)recognizer{ self.label.text = @"Horizontal swipe detected"; // 2s後擦除文本 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.label.text = @""; });}- (void)reportVerticalSwipe:(UIGestureRecognizer *)recognizer{ self.label.text = @"Vertical swipe detected"; // 2s後擦除文本 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.label.text = @""; });}@end
三、實現多指輕掃
//// ViewController.m// Swipes//// Created by Jierism on 16/8/4.// Copyright © 2016年 Jierism. All rights reserved.//#import "ViewController.h"@interface ViewController ()@property (weak, nonatomic) IBOutlet UILabel *label;@property (nonatomic) CGPoint gestureStartPoint;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. for (NSUInteger touchCount = 1; touchCount <= 5; touchCount++) { //建立兩個手勢辨識器 // 1、水平方向辨識器 UISwipeGestureRecognizer *horizontal = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(reportHorizontalSwipe:)]; horizontal.direction = UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight; [self.view addGestureRecognizer:horizontal]; // 2、垂直方向辨識器 UISwipeGestureRecognizer *vertical = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(reportVerticalSwipe:)]; vertical.direction = UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown; [self.view addGestureRecognizer:vertical]; } }- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}- (NSString *)descriptionForTouchCount:(NSUInteger)touchCount{ switch (touchCount) { case 1: return @"Single"; case 2: return @"Double"; case 3: return @"Triple"; case 4: return @"Quadruple"; case 5: return @"Quintuple"; default: return @""; }}- (void)reportHorizontalSwipe:(UIGestureRecognizer *)recognizer{ self.label.text = [NSString stringWithFormat:@"%@ Horizontal swipe detected",[self descriptionForTouchCount:[recognizer numberOfTouches]]]; // 2s後擦除文本 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.label.text = @""; });}- (void)reportVerticalSwipe:(UIGestureRecognizer *)recognizer{ self.label.text = [NSString stringWithFormat:@"%@ Vertical swipe detected",[self descriptionForTouchCount:[recognizer numberOfTouches]]]; // 2s後擦除文本 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.label.text = @""; });}@end
四、檢測多次輕點
//// ViewController.m// TapTaps//// Created by Jierism on 16/8/4.// Copyright © 2016年 Jierism. All rights reserved.//#import "ViewController.h"@interface ViewController ()@property (weak, nonatomic) IBOutlet UILabel *singleLabel;@property (weak, nonatomic) IBOutlet UILabel *doubleLabel;@property (weak, nonatomic) IBOutlet UILabel *tripleLabel;@property (weak, nonatomic) IBOutlet UILabel *quadrupleLabel;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 建立4個點選手勢辨識器 UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap)]; singleTap.numberOfTapsRequired = 1; singleTap.numberOfTouchesRequired = 1; // 附加到視圖 [self.view addGestureRecognizer:singleTap]; UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap)]; doubleTap.numberOfTapsRequired = 2; doubleTap.numberOfTouchesRequired = 1; [self.view addGestureRecognizer:doubleTap]; // 當doubleTap響應“失敗”才運行singleTap [singleTap requireGestureRecognizerToFail:doubleTap]; UITapGestureRecognizer *tripleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tripleTap)]; tripleTap.numberOfTapsRequired = 3; tripleTap.numberOfTouchesRequired = 1; [self.view addGestureRecognizer:tripleTap]; [doubleTap requireGestureRecognizerToFail:tripleTap]; UITapGestureRecognizer *quadrupleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(quadrupleTap)]; quadrupleTap.numberOfTapsRequired = 4; quadrupleTap.numberOfTouchesRequired = 1; [self.view addGestureRecognizer:quadrupleTap]; [tripleTap requireGestureRecognizerToFail:quadrupleTap];}- (void)singleTap{ self.singleLabel.text = @"Single Tap Detected"; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.singleLabel.text = @""; });}- (void)doubleTap{ self.doubleLabel.text = @"Double Tap Detected"; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.doubleLabel.text = @""; });}- (void)tripleTap{ self.tripleLabel.text = @"Triple Tap Detected"; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.tripleLabel.text = @""; });}- (void)quadrupleTap{ self.quadrupleLabel.text = @"Quadruple Tap Detected"; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.quadrupleLabel.text = @""; });}@end
五、檢測捏合和旋轉
#import <UIKit/UIKit.h>@interface ViewController : UIViewController<UIGestureRecognizerDelegate>@end
//// ViewController.m// PinchMe//// Created by Jierism on 16/8/4.// Copyright © 2016年 Jierism. All rights reserved.//#import "ViewController.h"@interface ViewController ()@property (strong,nonatomic) UIImageView *imageView;@end@implementation ViewController// 當前縮放比例,先前縮放比例CGFloat scale,previousScale;// 當前旋轉角度,先前旋轉角度CGFloat rotation,previousRotation;- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. previousScale = 1; UIImage *image = [UIImage imageNamed:@"yosemite-meadows"]; self.imageView = [[UIImageView alloc] initWithImage:image]; // 對映像啟用互動功能 self.imageView.userInteractionEnabled = YES; self.imageView.center = self.view.center; [self.view addSubview:self.imageView]; // 建立捏合手勢辨識器 UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(doPinch:)]; pinchGesture.delegate = self; [self.imageView addGestureRecognizer:pinchGesture]; // 建立旋轉手勢辨識器 UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(doRorate:)]; rotationGesture.delegate = self; [self.imageView addGestureRecognizer:rotationGesture];}- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ // 允許捏合手勢和旋轉手勢同時工作。否則,先開始的手勢辨識器會屏蔽另一個 return YES;}// 根據手勢辨識器中獲得的縮放比例和旋轉角度對映像進行變換- (void)transformImageView{ CGAffineTransform t = CGAffineTransformMakeScale(scale * previousScale, scale * previousScale); t = CGAffineTransformRotate(t, rotation + previousRotation); self.imageView.transform = t;}- (void)doPinch:(UIPinchGestureRecognizer *)gesture{ scale = gesture.scale; [self transformImageView]; if (gesture.state == UIGestureRecognizerStateEnded) { previousScale = scale * previousScale; scale = 1; }}- (void)doRorate:(UIRotationGestureRecognizer *)gesture{ rotation = gesture.rotation; [self transformImageView]; if (gesture.state == UIGestureRecognizerStateEnded) { previousRotation = rotation + previousRotation; rotation = 0; }}@end
六、自訂手勢
//// CheckMarkRecognizer.m// CheckPlease//// Created by Jierism on 16/8/4.// Copyright © 2016年 Jierism. All rights reserved.//#import "CheckMarkRecognizer.h"#import "CGPointUtils.h"#import <UIKit/UIGestureRecognizerSubclass.h> // 一個重要目的是使手勢辨識器的state屬性可寫,子類將使用這個機制斷言我們所觀察的手勢已成功完成// 設定檢測範圍static CGFloat const kMinimunCheckMarkAngle = 80;static CGFloat const kMaximumCheckMarkAngle = 100;static CGFloat const kMinimumCheckMarkLength = 10;@implementation CheckMarkRecognizer{ // 前兩個執行個體變數提供之前的線段 CGPoint lastPreviousPoint; CGPoint lastCurrentPoint; // 畫出的線段長度 CGFloat lineLengthSoFar;}// 用lastPreviousPoint和lastCurrentPoint組成第一條線段,跟第二條線段形成角度去完成手勢- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [super touchesBegan:touches withEvent:event]; UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:self.view]; lastPreviousPoint = point; lastCurrentPoint = point; lineLengthSoFar = 0.0;}- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ [super touchesMoved:touches withEvent:event]; UITouch *touch = [touches anyObject]; CGPoint previousPoint = [touch previousLocationInView:self.view]; CGPoint currentPoint = [touch locationInView:self.view]; CGFloat angle = angleBetweenLines(lastPreviousPoint, lastCurrentPoint, previousPoint, currentPoint); if (angle >= kMinimunCheckMarkAngle && angle <= kMaximumCheckMarkAngle && lineLengthSoFar > kMinimumCheckMarkLength) { self.state = UIGestureRecognizerStateRecognized; } lineLengthSoFar += distanceBetweenPoints(previousPoint, currentPoint); lastPreviousPoint = previousPoint; lastCurrentPoint = currentPoint;}@end
//// ViewController.m// CheckPlease//// Created by Jierism on 16/8/4.// Copyright © 2016年 Jierism. All rights reserved.//#import "ViewController.h"#import "CheckMarkRecognizer.h"@interface ViewController ()@property (weak, nonatomic) IBOutlet UIImageView *imageView;@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. CheckMarkRecognizer *check = [[CheckMarkRecognizer alloc] initWithTarget:self action:@selector(doCheck:)]; [self.view addGestureRecognizer:check]; self.imageView.hidden = YES;}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.}- (void)doCheck:(CheckMarkRecognizer *)check{ self.imageView.hidden = NO; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.imageView.hidden = YES; });}@end
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。