OC UI ——UIGestureRecognizer 手势识别

OC UI ------UIGestureRecognizer 手势识别

文章目录

  • [OC UI ------UIGestureRecognizer 手势识别](#OC UI ——UIGestureRecognizer 手势识别)
  • [一、什么是 UIGestureRecognizer?](#一、什么是 UIGestureRecognizer?)
    • [1.1 定义](#1.1 定义)
    • [1.2 好处](#1.2 好处)
    • [1.3 手势识别的层级关系](#1.3 手势识别的层级关系)
  • 二、手势识别核心原理:底层工作机制
    • [2.1 手势识别的完整流程](#2.1 手势识别的完整流程)
    • [2.2 手势识别器的核心状态(重点)](#2.2 手势识别器的核心状态(重点))
    • [2.3 事件回调机制](#2.3 事件回调机制)
  • 三、五大常用手势深度解析
    • [3.1 UITapGestureRecognizer(点击手势)](#3.1 UITapGestureRecognizer(点击手势))
      • [3.1.1 功能说明](#3.1.1 功能说明)
      • [3.1.2 核心属性(重点)](#3.1.2 核心属性(重点))
      • [3.1.3 完整代码演示(单击+双击)](#3.1.3 完整代码演示(单击+双击))
      • [3.1.4 常见问题与解决方案](#3.1.4 常见问题与解决方案)
    • [3.2 UILongPressGestureRecognizer(长按手势)](#3.2 UILongPressGestureRecognizer(长按手势))
      • [3.2.1 功能说明](#3.2.1 功能说明)
      • [3.2.2 核心属性(重点)](#3.2.2 核心属性(重点))
      • [3.2.3 完整代码演示(长按弹出菜单)](#3.2.3 完整代码演示(长按弹出菜单))
      • [3.2.4 关键注意点](#3.2.4 关键注意点)
    • [3.3 UIPanGestureRecognizer(拖拽平移手势)](#3.3 UIPanGestureRecognizer(拖拽平移手势))
      • [3.3.1 功能说明](#3.3.1 功能说明)
      • [3.3.2 核心属性与方法](#3.3.2 核心属性与方法)
      • [3.3.3 完整代码演示(拖拽视图自由移动)](#3.3.3 完整代码演示(拖拽视图自由移动))
      • [3.3.4 进阶技巧](#3.3.4 进阶技巧)
    • [3.4 UIPinchGestureRecognizer(捏合缩放手势)](#3.4 UIPinchGestureRecognizer(捏合缩放手势))
      • [3.4.1 功能说明](#3.4.1 功能说明)
      • [3.4.2 核心属性与方法](#3.4.2 核心属性与方法)
      • [3.4.3 完整代码演示(双指缩放图片)](#3.4.3 完整代码演示(双指缩放图片))
      • [3.4.4 关键注意点](#3.4.4 关键注意点)
    • [3.5 UIRotationGestureRecognizer(旋转手势)](#3.5 UIRotationGestureRecognizer(旋转手势))
      • [3.5.1 功能说明](#3.5.1 功能说明)
      • [3.5.2 核心属性与方法](#3.5.2 核心属性与方法)
      • [3.5.3 完整代码演示(双指旋转图片)](#3.5.3 完整代码演示(双指旋转图片))
  • 四、手势识别高级用法
    • [4.1 手势冲突的解决方法](#4.1 手势冲突的解决方法)
    • [4.2 自定义手势](#4.2 自定义手势)

一、什么是 UIGestureRecognizer?

1.1 定义

简单来说,我们之前通过 UIButton 实现点击交互,是"控件绑定事件";而手势识别是"脱离控件本身,直接监听屏幕动作"------无论是 View、ImageView、Label,甚至是空白区域,只要添加了手势识别器,就能响应对应的手指动作.

1.2 好处

在移动开发中,手势是用户与APP交互的主要方式之一,手势识别的核心价值体现在三个方面:

  • 打破控件限制:无需依赖按钮、滑块等可交互控件,任意视图都能实现复杂交互(如长按图片保存、拖拽图标排序);
  • 提升交互体验:模拟真实世界的操作逻辑(如双指缩放图片、旋转屏幕),让用户操作更自然、更流畅;
  • 简化开发流程:系统封装了常用手势,无需手动监听触摸事件(如 touchBegan、touchMoved),大幅减少代码量,降低开发难度。

1.3 手势识别的层级关系

要理解手势识别,必须明确它与 View、ViewController 的层级关系,这是后续避免手势冲突、实现复杂交互的关键:

  1. 触摸事件的传递顺序:屏幕接收用户触摸 → 传递给 UIWindow → 传递给最上层的 View → 传递给该 View 上的手势识别器;
  2. 手势识别器的归属:手势识别器(UIGestureRecognizer)是"附加"在 View 上的,一个 View 可以添加多个手势识别器,一个手势识别器也可以附加到多个 View 上;
  3. 与触摸事件的优先级:手势识别器会"拦截"触摸事件------当用户的动作被手势识别器识别后,该触摸事件就不会再传递给 View 本身(如 View 的 touchMoved 方法不会再触发)。

二、手势识别核心原理:底层工作机制

2.1 手势识别的完整流程

手势识别的整个过程分为 5 个阶段,从用户触摸屏幕到触发回调,每一步都有明确的逻辑:

  1. 触摸开始:用户手指按下屏幕,系统将触摸事件传递给对应 View 上的手势识别器;
  2. 手势分析:手势识别器开始分析触摸动作的特征(如手指数量、移动轨迹、停留时间);
  3. 状态判断:根据分析结果,手势识别器切换自身状态(如从"可能识别"到"识别成功");
  4. 事件回调:当手势识别成功或失败时,触发绑定的回调方法,执行业务逻辑;
  5. 触摸结束:用户手指离开屏幕,手势识别器重置状态,等待下一次触摸事件。

2.2 手势识别器的核心状态(重点)

UIGestureRecognizer 有 6 种核心状态,所有手势的识别过程,本质上都是状态的切换过程。

状态枚举 状态说明 典型场景
UIGestureRecognizerStatePossible 初始状态,手势识别器准备就绪,等待触摸事件 手势刚被添加到 View 上,未接收任何触摸
UIGestureRecognizerStateBegan 手势开始被识别(如长按手势达到最小长按时间) 长按手势,手指按下停留超过0.5秒(默认)
UIGestureRecognizerStateChanged 手势识别中,动作发生变化(如拖拽时手指移动、缩放时双指距离变化) 拖拽视图时,手指移动过程中;双指缩放图片时,手指距离变化
UIGestureRecognizerStateEnded 手势识别成功,手指离开屏幕 单击手势,手指按下后松开;拖拽手势,手指松开
UIGestureRecognizerStateCancelled 手势识别被取消(未完成识别) 长按手势时,手指未松开就拖动到屏幕外;系统中断手势(如来电)
UIGestureRecognizerStateFailed 手势识别失败(动作不符合手势要求) 双击手势,两次点击间隔超过默认时间;拖拽手势,手指按下后未移动

补充:所有手势识别器的初始状态都是 Possible,最终会走向 Ended(成功)、Cancelled(取消)或 Failed(失败),且状态一旦切换到这三种,会自动重置为 Possible,等待下一次触摸。

2.3 事件回调机制

手势识别器的回调的核心是"绑定目标-动作"(Target-Action),与 UIButton 的回调机制类似,但更灵活------可以绑定多个目标和动作,也可以动态添加、移除回调。

核心原理:当手势识别器的状态发生变化(如 Began、Changed、Ended)时,系统会自动调用绑定的动作方法,并且会将手势识别器本身作为参数传递给方法,方便我们在方法中获取手势的状态、位置等信息。

三、五大常用手势深度解析

UIGestureRecognizer 是一个抽象基类,我们无法直接实例化,只能使用它的子类------系统已经封装了 5 个最常用的手势子类,覆盖了 90% 以上的开发场景。

3.1 UITapGestureRecognizer(点击手势)

3.1.1 功能说明

最基础、最常用的手势,用于识别用户的"单击""双击""多击"动作(如点击图片查看大图、双击点赞、三击放大文本)。

3.1.2 核心属性(重点)

  • numberOfTapsRequired:需要点击的次数(默认1,单击;设为2,双击;设为3,三击);
  • numberOfTouchesRequired:需要同时点击的手指数量(默认1,单指点击;设为2,双指点击);
  • delaysTouchesEnded:是否延迟触摸结束事件(默认YES)------避免双击时,第一次点击的 Ended 事件被提前触发,导致双击识别失败。

3.1.3 完整代码演示(单击+双击)

objc 复制代码
#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) UIImageView *imgView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1. 创建图片视图(作为手势的载体)
    self.imgView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 300, 200)];
    self.imgView.image = [UIImage imageNamed:@"testImage"]; 
    self.imgView.userInteractionEnabled = YES; // 关键:默认UIImageView不可交互,必须开启
    [self.view addSubview:self.imgView];
    
    // 2. 创建单击手势
    UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapAction:)];
    singleTap.numberOfTapsRequired = 1; // 单击
    singleTap.numberOfTouchesRequired = 1; // 单指
    [self.imgView addGestureRecognizer:singleTap];
    
    // 3. 创建双击手势
    UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapAction:)];
    doubleTap.numberOfTapsRequired = 2; // 双击
    [self.imgView addGestureRecognizer:doubleTap];
    
    // 4. 解决单击与双击冲突:双击时,不触发单击(关键)
    [singleTap requireGestureRecognizerToFail:doubleTap];
}

// 单击回调
- (void)singleTapAction:(UITapGestureRecognizer *)gesture {
    NSLog(@"单击图片");
    // 查看大图
    UIImageView *bigImgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
    bigImgView.image = self.imgView.image;
    bigImgView.userInteractionEnabled = YES;
    bigImgView.backgroundColor = [UIColor blackColor];
    [self.view addSubview:bigImgView];
    
    // 给大图添加单击,点击关闭
    UITapGestureRecognizer *closeTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeBigImg:)];
    [bigImgView addGestureRecognizer:closeTap];
}

// 双击回调
- (void)doubleTapAction:(UITapGestureRecognizer *)gesture {
    NSLog(@"双击图片");
    // 放大图片
    [UIView animateWithDuration:0.3 animations:^{
        self.imgView.transform = CGAffineTransformScale(self.imgView.transform, 1.2, 1.2); // 放大1.2倍
    }];
}

// 关闭大图回调
- (void)closeBigImg:(UITapGestureRecognizer *)gesture {
    [gesture.view removeFromSuperview];
}

@end

3.1.4 常见问题与解决方案

  • 问题1:UIImageView 添加手势后不响应?------ 忘记设置 userInteractionEnabled = YES(默认NO);
  • 问题2:单击和双击冲突,双击时会先触发单击?------ 使用 requireGestureRecognizerToFail: 方法,让单击手势等待双击手势识别失败后再触发;

3.2 UILongPressGestureRecognizer(长按手势)

3.2.1 功能说明

识别用户"长按"动作,即手指按下屏幕后,停留一段时间不移动、不松开。常用场景:长按保存图片、长按删除图标、长按弹出菜单(如微信长按消息弹出删除/转发)。

3.2.2 核心属性(重点)

  • minimumPressDuration:最小长按时间(默认0.5秒)------ 手指按下后,停留超过这个时间,才会触发手势;
  • allowableMovement:允许的最大移动距离(默认10像素)------ 长按过程中,手指移动距离不超过这个值,手势仍会被识别;超过则识别失败;
  • numberOfTouchesRequired:需要同时长按的手指数量(默认1,单指长按)。

3.2.3 完整代码演示(长按弹出菜单)

objc 复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1. 创建标签(载体)
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, 350, 300, 40)];
    label.text = @"长按我弹出菜单";
    label.backgroundColor = [UIColor lightGrayColor];
    label.userInteractionEnabled = YES;
    label.tag = 100; // 加个tag方便识别
    [self.view addSubview:label];
    
    // 2. 创建长按手势
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressAction:)];
    longPress.minimumPressDuration = 0.6;
    longPress.allowableMovement = 15;
    [label addGestureRecognizer:longPress];
}

// 必须实现:让控制器可以成为第一响应者
- (BOOL)canBecomeFirstResponder {
    return YES;
}

// 必须实现:声明我们要响应哪些菜单方法
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(copyText:) || action == @selector(deleteText:)) {
        return YES;
    }
    return NO;
}

// 长按回调
- (void)longPressAction:(UILongPressGestureRecognizer *)gesture {
    if (gesture.state == UIGestureRecognizerStateBegan) {
        NSLog(@"长按开始");
        UILabel *targetLabel = (UILabel *)gesture.view;
        
        // 让控制器成为第一响应者(必须)
        [self becomeFirstResponder];
        
        UIMenuController *menu = [UIMenuController sharedMenuController];
        UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:@"复制" action:@selector(copyText:)];
        UIMenuItem *deleteItem = [[UIMenuItem alloc] initWithTitle:@"删除" action:@selector(deleteText:)];
        menu.menuItems = @[copyItem, deleteItem];
        
        [menu setTargetRect:targetLabel.bounds inView:targetLabel];
        [menu setMenuVisible:YES animated:YES];
    }
}

// 复制点击事件
- (void)copyText:(UIMenuController *)menu {
    NSLog(@"点击了复制");
    UILabel *label = [self.view viewWithTag:100];
    UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
    pasteboard.string = label.text;
}

// 删除点击事件
- (void)deleteText:(UIMenuController *)menu {
    NSLog(@"点击了删除");
    UILabel *label = [self.view viewWithTag:100];
    label.text = @"";
}

3.2.4 关键注意点

长按手势的回调方法会多次触发(Began、Changed、Ended 等状态都会触发),因此必须通过判断 gesture.state,只在需要的状态(如 Began)执行逻辑,避免重复操作。

3.3 UIPanGestureRecognizer(拖拽平移手势)

3.3.1 功能说明

识别用户"拖拽"动作,即手指按下屏幕后,持续移动。常用场景:拖拽视图调整位置(如拖拽图标、拖拽滑块)、滑动删除、下拉刷新(简化版)。

3.3.2 核心属性与方法

  • translationInView: 方法:获取手势在指定 View 中的平移距离(CGPoint 类型,x 为水平平移距离,y 为垂直平移距离);
  • velocityInView: 方法:获取手势的移动速度(CGPoint 类型,单位:像素/秒);
  • setTranslation: inView: 方法:重置平移距离(常用在拖拽过程中,避免平移距离累积);
  • minimumNumberOfTouches:最小拖拽手指数量(默认1);
  • maximumNumberOfTouches:最大拖拽手指数量(默认无限制)。

3.3.3 完整代码演示(拖拽视图自由移动)

objc 复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1. 创建可拖拽的视图
    UIView *dragView = [[UIView alloc] initWithFrame:CGRectMake(50, 420, 100, 100)];
    dragView.backgroundColor = [UIColor redColor];
    dragView.userInteractionEnabled = YES;
    [self.view addSubview:dragView];
    
    // 2. 创建拖拽手势
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
    pan.minimumNumberOfTouches = 1;
    pan.maximumNumberOfTouches = 1;
    [dragView addGestureRecognizer:pan];
}

// 拖拽回调
- (void)panAction:(UIPanGestureRecognizer *)gesture {
    // 1. 获取拖拽的平移距离(相对于父视图)
    CGPoint translation = [gesture translationInView:gesture.view.superview];
    
    // 2. 计算视图的新位置(原位置 + 平移距离)
    CGRect newFrame = gesture.view.frame;
    newFrame.origin.x += translation.x;
    newFrame.origin.y += translation.y;
    
    // 3. 限制视图不能超出屏幕
    CGFloat maxX = self.view.bounds.size.width - gesture.view.bounds.size.width;
    CGFloat maxY = self.view.bounds.size.height - gesture.view.bounds.size.height;
    newFrame.origin.x = MAX(0, MIN(newFrame.origin.x, maxX)); // 水平限制
    newFrame.origin.y = MAX(0, MIN(newFrame.origin.y, maxY)); // 垂直限制
    
    // 4. 更新视图位置
    gesture.view.frame = newFrame;
    
    // 5. 重置平移距离(关键:避免下次拖拽时,平移距离累积)
    [gesture setTranslation:CGPointZero inView:gesture.view.superview];
    
    // 6. 根据手势状态执行不同逻辑
    if (gesture.state == UIGestureRecognizerStateEnded) {
        // 拖拽结束,让视图轻微回弹
        [UIView animateWithDuration:0.2 animations:^{
            gesture.view.transform = CGAffineTransformScale(gesture.view.transform, 1.05, 1.05);
        } completion:^(BOOL finished) {
            [UIView animateWithDuration:0.1 animations:^{
                gesture.view.transform = CGAffineTransformIdentity;
            }];
        }];
    }
}

@end

3.3.4 进阶技巧

通过 velocityInView: 方法,可以实现"拖拽速度越快,视图移动越远"的效果(如拖拽结束后,根据速度让视图继续滑动一段距离),提升交互的流畅度。

3.4 UIPinchGestureRecognizer(捏合缩放手势)

3.4.1 功能说明

识别用户"双指捏合"或"双指张开"动作,用于调整视图的缩放比例。。

3.4.2 核心属性与方法

  • scale:缩放比例(默认1.0,即原始大小;大于1.0放大,小于1.0缩小);
  • velocity:缩放速度(单位:缩放比例/秒,正值表示放大,负值表示缩小);
  • setScale: 方法:设置初始缩放比例;
  • reset() 方法:重置缩放比例为1.0。

3.4.3 完整代码演示(双指缩放图片)

objc 复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.imgView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 300, 200)];
    self.imgView.image = [UIImage imageNamed:@"1"]; // 你的图片
    self.imgView.userInteractionEnabled = YES;
    self.imgView.contentMode = UIViewContentModeScaleAspectFit;
    [self.view addSubview:self.imgView];
    
    // 添加旋转手势
    UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationAction:)];
    rotation.delegate = self; 
    [self.imgView addGestureRecognizer:rotation];
}

// 正确的旋转方法
- (void)rotationAction:(UIRotationGestureRecognizer *)gesture {
    // 取当前手势的旋转角度
    CGFloat rotation = gesture.rotation;
    
    // 在现有 transform 基础上叠加旋转(关键写法)
    gesture.view.transform = CGAffineTransformRotate(gesture.view.transform, rotation);
    
    // 重置角度,防止叠加爆炸
    gesture.rotation = 0;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES; // 允许多个手势同时生效
}

3.4.4 关键注意点

捏合手势的 scale 属性是"相对值"(相对于上一次回调的缩放比例),因此必须在每次回调后将 scale 重置为1.0,否则缩放比例会不断累积,导致缩放失控。

3.5 UIRotationGestureRecognizer(旋转手势)

3.5.1 功能说明

识别用户"双指旋转"动作,用于调整视图的旋转角度。常用场景:旋转图片、旋转控件(如自定义旋钮)、调整画板笔触方向。

3.5.2 核心属性与方法

  • rotation:旋转角度(单位:弧度,默认0;正值表示顺时针旋转,负值表示逆时针旋转);
  • velocity:旋转速度(单位:弧度/秒,正值顺时针,负值逆时针);
  • setRotation: 方法:设置初始旋转角度;
  • reset() 方法:重置旋转角度为0。

补充:iOS 中,弧度与角度的转换公式:弧度 = 角度 × π / 180;角度 = 弧度 × 180 / π。

3.5.3 完整代码演示(双指旋转图片)

objc 复制代码
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1. 创建图片视图
    self.imgView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 300, 200)];
    self.imgView.image = [UIImage imageNamed:@"testImage"];
    self.imgView.userInteractionEnabled = YES;
    self.imgView.contentMode = UIViewContentModeScaleAspectFit;
    // 设置图片中心点(旋转中心,默认是视图中心)
    self.imgView.layer.anchorPoint = CGPointMake(0.5, 0.5); // 中心旋转
    [self.view addSubview:self.imgView];
    
    // 2. 创建旋转手势
    UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationAction:)];
    [self.imgView addGestureRecognizer:rotation];
}

// 旋转回调
- (void)rotationAction:(UIRotationGestureRecognizer *)gesture {
    // 1. 获取当前旋转角度(弧度)
    CGFloat currentRotation = gesture.rotation;
    
    // 2. 计算新的旋转角度(累积之前的旋转角度)
    CGFloat newRotation = gesture.view.transform.rotation + currentRotation;
    
    // 3. 更新视图旋转
    gesture.view.transform = CGAffineTransformMakeRotation(newRotation);
    
    // 4. 重置旋转角度(关键:避免下次旋转时,角度累积)
    gesture.rotation = 0.0;
    
}

@end

四、手势识别高级用法

4.1 手势冲突的解决方法

当一个 View 上添加多个手势,或多个 View 上的手势存在重叠时,会出现"手势冲突"(如单击与双击、拖拽与缩放)。解决手势冲突的核心是"设置手势的优先级"或"判断手势的触发条件",主要有 3 种方法:

方法1:使用 requireGestureRecognizerToFail: 方法

让一个手势等待另一个手势识别失败后,再触发自身。适用于"互斥手势"(如单击和双击)。

objc 复制代码
// 让单击手势等待双击手势识别失败后,再触发
[singleTap requireGestureRecognizerToFail:doubleTap];

方法2:实现手势识别协议(UIGestureRecognizerDelegate)

通过协议方法,手动判断手势是否可以识别、是否允许同时识别多个手势,灵活控制手势的触发。常用协议方法:

  • gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer::是否允许当前手势与其他手势同时识别(返回YES,允许同时识别;返回NO,不允许);
  • gestureRecognizer:shouldReceiveTouch::是否允许手势接收触摸事件(可根据触摸位置、手指数量等条件,控制手势是否生效);
  • gestureRecognizerShouldBegin::手势是否应该开始识别(返回YES,开始识别;返回NO,拒绝识别)。
objc 复制代码
// 示例:解决拖拽与缩放手势的冲突,允许同时识别
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    // 判断两个手势是否是拖拽和缩放
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
        return YES; // 允许同时识别,实现拖拽的同时缩放
    }
    return NO;
}

方法3:调整手势的 enabled 属性

根据业务逻辑,动态启用或禁用手势。例如:当图片放大到最大比例时,禁用缩放手势;当拖拽到屏幕边缘时,禁用拖拽手势。

objc 复制代码
// 禁用缩放手势
self.pinchGesture.enabled = NO;
// 启用缩放手势
self.pinchGesture.enabled = YES;

4.2 自定义手势

系统提供的 5 个手势可以满足大部分场景,但如果需要实现特殊手势(如滑动轨迹识别、手势密码、双指拖拽),就需要自定义手势。

自定义手势的核心步骤:

  1. 创建 UIGestureRecognizer 的子类;
  2. 重写触摸事件方法(touchesBegan:withEvent:、touchesMoved:withEvent:、touchesEnded:withEvent:);
  3. 在触摸事件中,分析触摸动作的特征(如轨迹、手指数量);
  4. 根据特征,切换手势的状态(如识别成功则设置为 Ended);
  5. 绑定回调方法,执行业务逻辑。
相关推荐
阿正的梦工坊6 小时前
React:构建用户界面的JavaScript库
javascript·react.js·ui
hhb_6186 小时前
Swift技术难点梳理与实战案例解析
开发语言·ios·swift
MonkeyKing7 小时前
iOS UICollectionView 高可用架构:复用、预加载、横向嵌套实战详解
ios
冰凌时空7 小时前
30 Apps 第 2 天:待办清单 App —— MVVM + Combine 响应式 UI
ios·openai·ai编程
冰凌时空7 小时前
手写 Swift 运行时:objc_msgSend 的汇编级解析
ios·openai·ai编程
2601_956002818 小时前
AdGuardPro_TS.ipa2026最新版ipa 下载后浏览器无广告 官方正版2026最新版pc免费下载(看到请立即转存 资源随时失效)ios必下
macos·ios·cocoa·ipa
Daniel_Coder8 小时前
iOS Widget 开发-12:Widget 深度链接与导航
ios·swiftui·swift·widget·intents
ZC跨境爬虫8 小时前
跟着 MDN 学 HTML day_62:(HTML调试与常见错误修复指南)
java·前端·javascript·ui·html·媒体