iOS的手势识别器
一. 监听触摸事件的做法
如果想监听一个view上面的触摸事件,不使用手势实现的步骤
(1). 自定义一个view
(2). 实现view的touches方法,在方法内部实现具体处理代码
通过touches方法监听view触摸事件,有很明显的几个缺点
(1). 必须得自定义view
(2). 由于是在view内部的touches方法中监听触摸事件,因此默认情况下,无法让其他外界对象监听view的触摸事件
(3). 不容易区分用户的具体手势行为
ios 3.2之后,苹果推出了手势识别功能(gesture recognizer),在触摸事件处理方面,大大简化了开发者的开发难度
二. 手势识别器简介
为了完成手势识别,必须借助于手势识别器:uigesturerecognizer
利用uigesturerecognizer,能轻松识别用户在某个view上面做的一些常见手势
uigesturerecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能处理具体的手势
uigesturerecognizer的子类
uitapgesturerecognizer(敲击)
uipinchgesturerecognizer(捏合,用于缩放)
uipangesturerecognizer(拖拽)
uiswipegesturerecognizer(轻扫)
uirotationgesturerecognizer(旋转)
uilongpressgesturerecognizer(长按)
三. uigesturerecognizer的常见属性和方法
uigesturerecognizer继承于nsobject
// 初始化手势要触发的对象与事件 - (instancetype)initwithtarget:(nullable id)target action:(nullable sel)action // 添加手势要触发的对象与事件 - (void)addtarget:(id)target action:(sel)action; // 移除手势要触发的对象与事件 - (void)removetarget:(nullable id)target action:(nullable sel)action; // 手势状态 @property(nonatomic,readonly) uigesturerecognizerstate state; // 代理 @property(nullable,nonatomic,weak) id delegate; // 手势是否可用,默认yes @property(nonatomic, getter=isenabled) bool enabled; // 只读,手势所属的视图 @property(nullable, nonatomic,readonly) uiview *view; // 默认yes.意思就是说一旦手势被识别,那么就调用[touchview touchescancelled:withevent] @property(nonatomic) bool cancelstouchesinview; // 默认no.意思就是再手势识别成功之前,touchobj还是要分发到touchview. // 设置为yes的时候就表示从手势识别成功之前touchobj不给touchview分发 @property(nonatomic) bool delaystouchesbegan; // 默认yes:在手势识别成功之前,touchesended不会被调用。 // 设置为no:在手势识别成功之前,touchesended会被调用 @property(nonatomic) bool delaystouchesended; // 当指定的识别器(调用者)识别失败,才去识别另一个识别器othergesturerecognizer - (void)requiregesturerecognizertofail:(uigesturerecognizer *)othergesturerecognizer; // 获取手势识别器的触摸点 - (cgpoint)locationinview:(nullable uiview*)view; // 获取手势识别器的触摸点个数 - (nsuinteger)numberoftouches; // 指定触摸点的位置 - (cgpoint)locationoftouch:(nsuinteger)touchindex inview:(nullable uiview*)view;
四. uigesturerecognizer代理
注意: 使用多个手势必须使用代理
// 是否允许触发手势 - (bool)gesturerecognizershouldbegin:(uigesturerecognizer *)gesturerecognizer; // 是否允许多个同时支持多个手势,默认不允许,手势必须要设置代理 - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldrecognizesimultaneouslywithgesturerecognizer:(uigesturerecognizer *)othergesturerecognizer; // 这个方法在这两个gesture recognizers中的任意一个将堵塞另一个的触摸事件时调用, // 如果返回yes,则两个gesture recognizers可同时识别, // 如果返回no,则并不保证两个gesture recognizers必不能同时识别, // 因为另外一个gesture recognizer的此方法可能返回yes。 // 也就是说两个gesture recognizers的delegate方法只要任意一个返回yes,则这两个就可以同时识别; // 只有两个都返回no的时候,才是互斥的。默认情况下是返回no - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldrequirefailureofgesturerecognizer:(uigesturerecognizer *)othergesturerecognizer ns_available_ios(7_0); // 是否允许手势识别器识别失败的时候使用另一个识别器othergesturerecognizer - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldberequiredtofailbygesturerecognizer:(uigesturerecognizer *)othergesturerecognizer ns_available_ios(7_0); // 是否允许接收触摸点 - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldreceivetouch:(uitouch *)touch; // 是否允许接收长按点 - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldreceivepress:(uipress *)press;
五. uigesturerecognizer的子类常见属性和方法
1. uitapgesturerecognizer(敲击)
// 需要连续敲击几次才可触发,默认1次 @property (nonatomic) nsuinteger numberoftapsrequired; // 需要几根手指一起敲击才可触发,默认1根 @property (nonatomic) nsuinteger numberoftouchesrequired __tvos_prohibited;
2. uipinchgesturerecognizer(捏合,用于缩放)
提示: 模拟器快捷键:opsin + shift 向上拖“两个触摸点”
// 缩放比例 @property (nonatomic) cgfloat scale; // 缩放速度 @property (nonatomic,readonly) cgfloat velocity;
3. uipangesturerecognizer(拖拽)
// 拖动的最短距离 @property (nonatomic) nsuinteger minimumnumberoftouches __tvos_prohibited; // 拖动的最长距离 @property (nonatomic) nsuinteger maximumnumberoftouches __tvos_prohibited; // 在指定的view上得坐标 - (cgpoint)translationinview:(nullable uiview *)view; // 设置在view中移动以后的坐标为translation - (void)settranslation:(cgpoint)translation inview:(nullable uiview *)view; // 拖动view,返回的值就用于计算view相对于父控件拖动的速度 - (cgpoint)velocityinview:(nullable uiview *)view;
4. uiswipegesturerecognizer(轻扫)
// 需要几根手指一起轻扫才可触发,默认1根 @property(nonatomic) nsuinteger numberoftouchesrequired __tvos_prohibited; // 设置轻扫方向 @property(nonatomic) uiswipegesturerecognizerdirection direction;
5. uirotationgesturerecognizer(旋转)
// 旋转角度 @property (nonatomic) cgfloat rotation; // 旋转速度 @property (nonatomic,readonly) cgfloat velocity;
6. uilongpressgesturerecognizer(长按)
注意: 长安手势一般会触发两次,所有一般为了只做一次,要做一次判断
// 需要连续长按几次才可触发,默认0次 @property (nonatomic) nsuinteger numberoftapsrequired; // 需要几根手指一起长按才可触发,默认1根 @property (nonatomic) nsuinteger numberoftouchesrequired __tvos_prohibited; // 最小长按时间 @property (nonatomic) cftimeinterval minimumpressduration; // 允许移动距离 @property (nonatomic) cgfloat allowablemovement;
六. 手势的具体使用
#import "viewcontroller.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. [self setuptap]; [self setuplongpress]; [self setupswipe]; [self setuprotation]; [self setuppinch]; [self setuppan]; } #pragma mark - 点按手势 - (void)setuptap { uitapgesturerecognizer *gesturerecognizer = [[uitapgesturerecognizer alloc] initwithtarget:self action:@selector(actionuptap)]; // 多个手势必须要代理 gesturerecognizer.delegate = self; [_imageview addgesturerecognizer:gesturerecognizer]; } - (void)actionuptap { nslog(@"点按手势"); } #pragma mark - 长按手势 - (void)setuplongpress { uilongpressgesturerecognizer *gesturerecognizer = [[uilongpressgesturerecognizer alloc] initwithtarget:self action:@selector(actionlongpress)]; gesturerecognizer.delegate = self; [_imageview addgesturerecognizer:gesturerecognizer]; } - (void)actionlongpress { nslog(@"长按手势"); } #pragma mark - 轻扫手势 - (void)setupswipe{ // 默认向右轻扫,如果要同时有多个轻扫方向,必须要创建轻扫对象 uiswipegesturerecognizer *gesturerecognizerright = [[uiswipegesturerecognizer alloc] initwithtarget:self action:@selector(actionswipe)]; [_imageview addgesturerecognizer:gesturerecognizerright]; uiswipegesturerecognizer *gesturerecognizerleft = [[uiswipegesturerecognizer alloc] initwithtarget:self action:@selector(actionswipe)]; // 向左轻扫 gesturerecognizerleft.direction = uiswipegesturerecognizerdirectionleft; [_imageview addgesturerecognizer:gesturerecognizerleft]; uiswipegesturerecognizer *gesturerecognizerup = [[uiswipegesturerecognizer alloc] initwithtarget:self action:@selector(actionswipe)]; // 向上轻扫 gesturerecognizerup.direction = uiswipegesturerecognizerdirectionup; [_imageview addgesturerecognizer:gesturerecognizerup]; uiswipegesturerecognizer *gesturerecognizerdown = [[uiswipegesturerecognizer alloc] initwithtarget:self action:@selector(actionswipe)]; // 向下轻扫 gesturerecognizerdown.direction = uiswipegesturerecognizerdirectiondown; [_imageview addgesturerecognizer:gesturerecognizerdown]; } - (void)actionswipe { nslog(@"轻扫手势"); } #pragma mark - 旋转手势 - (void)setuprotation { uirotationgesturerecognizer *gesturerecognizer = [[uirotationgesturerecognizer alloc] initwithtarget:self action:@selector(actionrotation:)]; gesturerecognizer.delegate = self; [_imageview addgesturerecognizer:gesturerecognizer]; } - (void)actionrotation:(uirotationgesturerecognizer *)rotation { _imageview.transform = cgaffinetransformrotate(_imageview.transform, rotation.rotation); // 复位 rotation.rotation = 0; } #pragma mark - 捏合手势 - (void) setuppinch { uipinchgesturerecognizer *gesturerecognizer = [[uipinchgesturerecognizer alloc] initwithtarget:self action:@selector(actionpinch:)]; gesturerecognizer.delegate = self; [_imageview addgesturerecognizer:gesturerecognizer]; } - (void)actionpinch:(uipinchgesturerecognizer *)pinch { _imageview.transform = cgaffinetransformscale(_imageview.transform, pinch.scale, pinch.scale); // 复位 pinch.scale = 1; } #pragma mark - 拖拽手势 - (void)setuppan { uipangesturerecognizer *gesturerecognizer = [[uipangesturerecognizer alloc] initwithtarget:self action:@selector(actionpan:)]; gesturerecognizer.delegate = self; [_imageview addgesturerecognizer:gesturerecognizer]; } - (void)actionpan:(uipangesturerecognizer *)pan { //nslog(@"%ld",[pan numberoftouches]); // 获取手势的触摸点 // cgpoint curp = [pan locationinview:self.imageview]; cgpoint pantrans = [pan translationinview:_imageview]; _imageview.transform = cgaffinetransformtranslate(_imageview.transform, pantrans.x, pantrans.y); // 复位 [pan settranslation:cgpointzero inview:_imageview]; } #pragma mark - 手势代理 // 是否允许多个同时支持多个手势,默认不允许,手势必须要设置代理 - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldrecognizesimultaneouslywithgesturerecognizer:(uigesturerecognizer *)othergesturerecognizer { return yes; } // 是否允许触发手势事件 - (bool)gesturerecognizershouldbegin:(uigesturerecognizer *)gesturerecognizer { return yes; } // 是否允许接收触摸点 - (bool)gesturerecognizer:(uigesturerecognizer *)gesturerecognizer shouldreceivetouch:(uitouch *)touch { return yes; } @end
上一篇: cf444E. DZY Loves Planting(并查集)
下一篇: 吃饼干也能玩出花样