欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS的手势识别器

程序员文章站 2022-05-11 14:43:22
一. 监听触摸事件的做法 如果想监听一个view上面的触摸事件,不使用手势实现的步骤 (1). 自定义一个view (2). 实现view的touches方法,在方法内部实现具体处理代码 通过tou...

一. 监听触摸事件的做法

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