当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS的手势识别器

iOS的手势识别器

2018年09月16日  | 移动技术网移动技术  | 我要评论

一. 监听触摸事件的做法

如果想监听一个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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网