IOS 定义手势监听器详解,利用 UIGestureRecognizer 进行捏合、旋转、平移、点击、长按手势事件响应

IOS中我们可以通过UITouch进行触摸事件监听,但是UITouch实现捏合、旋转、长按等手势事件监听非常麻烦。IOS中提供 UIGestureRecognizer 的子类帮我们简洁等实现捏合、旋转等特殊手势监听。并且一个视图可添加多个不同等手势监听器。

开启userInteractionEnabled

IOS 中UIView 默认是不可响应事件的,我们需要开启 userInteractionEnabled 方可进行事件响应。下面代码中我们创建了一个图片视图,并且开始事件响应。UIView 通过 addGestureRecognizer 进行添加手势监听器和 removeGestureRecognizer删除手势监听器

// 创建图片视图
- (void) creareImg {UIImage* image = [UIImage imageNamed:@"zz.jpeg"];_imageView = [[UIImageView alloc] initWithImage:image];UIScreen* screen = [UIScreen mainScreen];const int width = 200;const int height = 100;const float x = screen.bounds.size.width / 2 - width / 2;const float y = screen.bounds.size.height / 2 - height;_imageView.frame = CGRectMake(x, y, width, height);_imageView.userInteractionEnabled = YES;[self.view addSubview:_imageView];
}

了解UIGestrueRecognizer

在开始使用自定义手势之前我们先了解一下 UIGestrueRecognizer 的,因为自定义都是基于 UIGestrueRecognizer 继承实现的。 UIGestrueRecognizer 是一个手势监听器,它可以设置多个手指同时触发触发事件等行为。它具有代理协议 UIGestureRecognizerDelegate 下面我来看一下它主要的属性和API、代理方法。

属性
名称类型说明默认值
stateUIGestureRecognizerState当前手势状态,可分为手势开始,手势改变,手势结束等等
enabledBOOL是否启用YES
viewUIView手势监听的视图
requiresExclusiveTouchTypeBOOL是否忽略其他手势类型,设置为YES将只响应一种手势类型NO
numberOfTouchesNSUInteger多少根手指触发手势1
API
  • - (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 删除事件监听函数
  • - (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer 添加其他手势冲突失效器,当触发当前手势时,指定的手势将失效。
  • - (CGPoint)locationInView:(nullable UIView*)view 获取相对于指定视图的坐标位置
  • - (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view 获取指定手指相对指定视图的坐标位置
代理协议
  • - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 手势准备开启时候触发,返回NO则取消手势。

  • - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 当手势与其他手势同时发生识别时候触发,返回YES运行两个手势同时进行,返回NO则阻止同时识别。

  • - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 是否给事件接收手指。在手势开始触发事件触发前触发,返回NO可以阻止事件获取触摸的手指。

  • - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press 是否给按下事件接收手指,在按下手势事件触发前触发。返回NO可阻止事件获取触摸的手指。

我们了解清除GestureRecognizer 类,下面我们来了解其子类手势的使用。

UITapGestureRecognizer 点击手势

点击手势,可设置手指数量、点击次数触发的手势

// 创建点击手势
- (void) createTapGes {_imageView.userInteractionEnabled = YES; // 开启响应事件属性UITapGestureRecognizer* tapOneGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(big)]; // 创建手势tapOneGes.numberOfTapsRequired = 1; // 触发事件的点击次数tapOneGes.numberOfTouchesRequired = 1; // 触发事件的手指数量[_imageView addGestureRecognizer:tapOneGes]; // 添加手势监听器
}
// 点击触发事件
- (void) big {UIScreen* screen = [UIScreen mainScreen];[UIView beginAnimations:nil context:nil]; // 开始布局动画_imageView.frame = CGRectMake(0, 0, screen.bounds.size.width, screen.bounds.size.height);[UIView commitAnimations]; // 结束布局动画
}

UIPinchGestureRecognizer 捏合手势

捏合手势,表示双指捏合缩放的手势触发。常用于对图片查看缩放事件监听

// 捏合手势
- (void) createPinchGes {UIPinchGestureRecognizer* pinch = [[UIPinchGestureRecognizer alloc] init]; // 创建手势[pinch addTarget:self action:@selector(scale:)]; // 添加事件函数pinch.delegate = self; // 设置代理[_imageView addGestureRecognizer:pinch]; // 视图添加手势监听器
}- (void) scale: (UIPinchGestureRecognizer*) pinch {UIView* IView = pinch.view; // 获取监听的视图CGAffineTransform transiform = CGAffineTransformScale(IView.transform, pinch.scale, pinch.scale); // 计算缩放后的矩阵if (transiform.a < 0.4) { // 缩放小于0.4阻止transiform.a = 0.4;transiform.d = 0.4;}IView.transform = transiform; // 重新设置矩阵pinch.scale = 1; // 重置缩放矩阵,否则手势会一直累加
}// 添加允许多个手势触发代理函数
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {return  YES;
}

上面代码中我们通过获取捏合手势的scale 属性获取用户捏合缩放的大小。并且使用内置api CGAffineTransformScale 重新计算了视图的2D矩阵(矩阵表示图像变形,可以了解一下图形学),注意!最后一步中必须重置手势的scale 否则会一直累加导致计算矩阵错误,如果不想重置的话那就需要修改 CGAffineTransformScale的第一个参数为基础矩阵参数。

UIRotationGestureRecognizer 旋转手势

旋转手势,可获取用户手指旋转的角度。

// 旋转手势
- (void) createRotateGes {UIRotationGestureRecognizer* rotate = [[UIRotationGestureRecognizer alloc] init];[rotate addTarget:self action:@selector(rotate:)];rotate.delegate = self;[_imageView addGestureRecognizer:rotate];
}
// 旋转触发事件
- (void) rotate: (UIRotationGestureRecognizer*) rotate {UIView* IView = rotate.view;IView.transform =  CGAffineTransformRotate(IView.transform, rotate.rotation); // 重新计算视图矩阵rotate.rotation = 0;
}

UIPanGestureRecognizer 平移手势

平移动手势,比较简单就是手指移动时候触发,但是提供平移的位置和平移的速度

// 平移手势
- (void) createPanGes {UIPanGestureRecognizer* pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];pan.delegate = self;[_imageView addGestureRecognizer:pan];
}
- (void) pan: (UIPanGestureRecognizer*)pan {CGPoint speed = [pan velocityInView:_imageView]; // 获取移动速度NSLog(@"x速度= %f, y速度= %f", speed.x, speed.y);CGPoint translation = [pan translationInView:_imageView]; // 获取移动矩阵CGAffineTransform transform = CGAffineTransformTranslate(_imageView.transform, translation.x, translation.y);_imageView.transform = transform;
}

UILongPressGestureRecognizer 长按手势

长按对应视图触发手势,可设置手指数量和手指长按时间

// 长按手势
- (void) createLongPassGes {UILongPressGestureRecognizer* longPass = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(pass:)];longPass.minimumPressDuration = 1; // 设置长按触发时间,默认0.5[_imageView addGestureRecognizer: longPass];
}- (void)pass: (UILongPressGestureRecognizer*) longPass {if (longPass.state == UIGestureRecognizerStateBegan) {NSLog(@"开始长按");} else if (longPass.state == UIGestureRecognizerStateEnded) {NSLog(@"结束长按");} else if (longPass.state == UIGestureRecognizerStateChanged) {NSLog(@"长按发生改变");}
}

UISwipeGestureRecognizer 轻滑手势

轻滑手势,类似我们的平移手势。但是轻滑不同的是在用户快速滑动时候速度,并且只提供滑动方向。

// 创建轻滑手势
- (void) createSwipe {UISwipeGestureRecognizer* swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swiper:)];swipe.direction = UISwipeGestureRecognizerDirectionDown;[_imageView addGestureRecognizer: swipe];swipe.delegate = self;
}- (void) swiper: (UISwipeGestureRecognizer*)swiper {NSLog(@"发生向下滑动");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/563861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

abb限位开关已打开drv1_Telemecanique传感器限位开关产品系列

Telemecanique传感器Telemecanique传感器&#xff0c;是施耐德电气旗下专精于传感器产品的知名品牌&#xff0c;已有百年历史。被公认为全球传感器领域的专家。从机电式到电子式产品&#xff0c;从检测到识别再到距离测量&#xff0c;我们拥有覆盖广泛的传感器产品线。我们已成…

关于Vue 3.0 的改进 Proxy 代理实现数据驱动视图

Vue 3.0 中使用了 Proxy 对象代理进行拦截实现了数据绑定视图的驱动操作。弥补了vue2.0中的局限&#xff0c;比如属性删除增加监听、对数组基于下标的修改、长度变化等等。 参考一下网上流传的机制图 Proxy 是什么&#xff1f; 首先我们来了解一下Proxy是什么。Proxy不是简单…

两边双虚线是什么意思_行星减速机生产厂家解析行星减速机双支撑与单支撑

经常会有客户咨询合富源机电小编&#xff1a;行星减速机双支撑和行星减速机单支撑是什么意思&#xff1f;接下来富源机电小编就为大家讲解一下行星减速机双支撑和行星减速机单支撑。1、行星减速机双支撑和行星减速机单支撑的含义行星减速机双支撑和行星减速机单支撑指的是齿轮的…

Xcode11 后Appdelegate自定义UIWindow对象失败详解。

在Xcode11前我们可以在AppDelegate的钩子didFinishLaunchingWithOptions进行自定义UIWindow对象。但是Xcode11后自定义UIWindow会报错无法启动APP。 是因为iOS13中AppDelegate的职责发生了改变&#xff1a; iOS13之前&#xff0c;AppDelegate全权处理App生命周期和UI生命周期&a…

python预测疾病_吴裕雄--天生自然python机器学习:使用Logistic回归从疝气病症预测病马的死亡率...

&#xff0c;除了部分指标主观和难以测量外&#xff0c;该数据还存在一个问题&#xff0c;数据集中有30%的值是缺失的。下面将首先介绍如何处理数据集中的数据缺失问题&#xff0c;然 后 再 利 用 Logistic回 归和随机梯度上升算法来预测病马的生死。准备数据&#xff1a;处理被…

IOS中的事件响应链,事件冒泡机制基本了解

本文主要讲解IOS中事件响应链&#xff0c;即事件冒泡机制。做过web开发的同学应该知道js事件冒泡是从主响应元素一层一层的向父级冒泡事件&#xff0c;在ios亦是如此&#xff0c;但是不同是ios中&#xff0c;如果冒泡链中有一方对事件进行响应处理后会截止后续对冒泡行为不同于…

板子制作_工厂制作风管VS现场制作有什么区别?

一、传统风管与酚醛风管对比中央空调传统送风管道通常内层采用铁皮或玻璃钢&#xff0c;外裹保温材料&#xff0c;最外面用铝箔进行缠绕&#xff0c;这使得送风管重而大、施工安装费工费时、外观差、气密性低、能耗大。传统的风管已不能满足快速增长的市场需求及人们对室内环境…

关于 NODE.js 并行线程 worker_threads 的使用与详解。

javascript 是单线程&#xff0c;那么node.js属于服务端语言改如何实现其他语言中的并发线程执行呢&#xff1f;在node V10只有 child_process&#xff0c;cluster的API来开启多子进程&#xff0c;多进程。进程并不是子线程&#xff0c;无法内存共享。在nodeV10后引入worker_th…

IOS 多层级路由导航控制器 NavigationControoller 实现路由切换

IOS 导航控制器分为多层级导航控制器naviagtionController 和平行分栏控制器 UITabBar&#xff08;底部切换栏&#xff09;。IOS导航控制器是什么呢&#xff1f;其实就是我们web的路由切换功能&#xff0c;只不过在app开发切换是ViewController。 什么是导航控制器 NavigationC…

前端性能优化篇——浏览器同域名并发请求对限制

在浏览器同域名并发请求都产生并发数限制&#xff0c;并发限制通常是4&#xff5e;8以内&#xff0c;那么来了解浏览器请求并发限制的原因和优化手段。浏览器并发数量统计 浏览器为什么要请求并发数限制&#xff1f;在了解优化手段之前我们先了解浏览器限制并发请求的原因1.对操…

帧大小超过交换机mtu_交换机的三种交换方式

交换机是一种用于电&#xff08;光&#xff09;信号转发的网络设备&#xff0c;它可以为接入交换机的任意两个网络节点提供独享的电信号通路。交换机拥有一条高带宽的背部总线和内部交换矩阵&#xff0c;在同一时刻可进行多个端口对之间的数据传输&#xff0c;交换机的传输模式…

前端性能优化篇——浏览器http同域名并发请求对限制

在浏览器同域名并发请求都产生并发数限制&#xff0c;并发限制通常是4&#xff5e;8以内。那么我们将来了解浏览器请求并发限制的原因和优化手段。 浏览器并发数量统计 浏览器为什么要请求并发数限制&#xff1f; 在了解优化手段之前我们先了解浏览器限制并发请求的原因 1.对操…

二元函数洛必达求极限_洛必达法则的几个例子

洛必达法则(LHpitals rule)是在一定条件下通过分子分母分别求导再求极限来确定未定式值的方法。 插入一个八卦: 据说洛必达法则是富二代洛必达买来的。喜欢搞数学却苦无天分的贵族洛必达用三百个里弗尔(一里弗尔相当于一磅银子)成功地从伯努力手里买到了这个定理。因此17世…

React-Native 获取设备当前网络状态 NetInfo

react-native 应用获取设备网络状态可以使用 NetInfo 包进行获取。 NetInfo NetInfo 模块可以获取设备当前的联网状态&#xff0c;可以订阅和一次性获取网络状态。以前在react-native集成&#xff0c;现在已经单独移到 react-native-community 社区管理。 安装(IOS需要pod in…

javascript V8引擎垃圾收集机制

V8引擎使用的垃圾收集机制是标记清除&#xff0c;那么javascript在垃圾收集会阻塞其他程序执行。V8引擎使用了增量标记的方式进行优化 增量标记 V8不是直接对整个栈堆遍历标记&#xff0c;而是标记一部分堆后回复正常执行。下次GC将从上一次停止对位置继续进行标记。这样允许在…

rstudio的数据集怎么建立和保存_这个40M的小工具助你在windows下处理数据如虎添翼...

使用windows系统时&#xff0c;如何获取一个大小为1M的文件的行数呢&#xff1f;一般是选择用excel或notepad等软件打开文件&#xff0c;然后查看最后一行的行号&#xff0c;那如果是想快速获取一个大小为1G的文件的行数呢&#xff1f;或是想快速获取100个大小为1M的文件的行数…

mongo 唯一约束索引_Java:MySQL 基础知识+索引相关

阅读本文前&#xff0c;请您先点击上面的蓝色字体&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到最新文章了。每天都有分享。完全是免费订阅&#xff0c;请放心关注。注&#xff1a;本文转载自网络&#xff0c;不代表本平台立场&#xff0c;仅供读者参考&…

Javascript性能优化【内联缓存】 V8引擎特性

javascript 是单线程、动态类型语言&#xff0c;那么我们在编码时候如何编写性能最优代码呢&#xff1f;下面将讲解V8引擎的内联优化。利用内联缓存这个特性我们可以编写更加优秀的代码。 什么是内联缓存 引用官方的描述&#xff1a;内联缓存&#xff08;Inline caching&#…

bootstrap 垂直居中 布局_CSS3 flex 布局必须要掌握的知识点

flex 布局已经流行好久了&#xff0c;从最开始大家都在用非官方标准的 box 布局(display: box; display: -webkit-box;)&#xff0c;到后来的各种兼容写法&#xff0c;再到后来基本上就是只用 flex 了。毕竟标准就是标准&#xff0c;虽然有时候会迟到&#xff0c;但是最终肯定还…

关于微信浏览器H5 React,Vue工程化项目input无法自动聚焦疑难杂症排查

前言 最近使用React开发微信H5搜索框自动聚焦功能&#xff0c;发现路由跳转页面后无法自动聚焦。尝试了各种方法均不生效…后来发型是异步加载组件问题&#xff0c;个人估计是微信浏览器在异步组件加载完成后导致节点失焦。 尝试过的解决方法 input 属性 autofocus —— 不生…