iOS开发之事件的产生和传递
2015-12-02 12:44
651 查看
之前在做画板应用的时候,我们使用了三个方法:
其实这些方法是触摸事件的方法,其中还有一个方法:
还记得我们使用这些方法干了什么吗?
我们使用这些方法实现了手指在view 上的触摸事件处理。touchesBegan知道手指开始触摸的位置;touchesMoved知道手指移动过程中的位置;touchesEnded还知道手指触摸结束时候的位置,以此推断touchesCancelled方法可以告诉我们手指触摸被中止(如来电)时候的位置。
本章将介绍触摸事件的处理过程。
先了解一些和触摸事件有关的知识
1)用户在使用app的过程中,会产生各种各样的事件。iOS中的事件分为3大类型(引用官当文档的图片):
触摸事件 加速计事件 远程控制器事件
2)响应者对象:iOS中不是任何对象都能处理事件,只有继承自UIResponder的对象才能接受并处理事件,我们称之为“响应者对象”。
UIApplication、UIController、UIView都是继承自UIResponder,因此它们都是响应者对象,都能接受并处理事件。
3)UIResponder:为什么继承自UIResponder就能接受并处理事件呢。
因为UIResponder内部提供了以下方法来专门处理事件:
触摸事件方法:
加速计事件方法:
远程控制事件方法
这里我们主要介绍触摸事件,所以对触摸事件方法做一下简单说明。拿之前自定义画板的例子。
画板是继承自UIView,UIView是继承自UIResponder。可以覆盖触摸方法来处理不同的事件:
一根或多根手指开始触摸view,系统会自动调用下面方法
一根或多根手指在view上移动,系统会自动调用下面方法(随着手指的移动,系统会一直调用这个方法)
一根或多根手指离开view,系统会自动调用下面方法(触摸事件结束)
一根或多根手指在view上的触摸被中止(如来电),系统会自动调用下面方法
注意:touches中存放的都是UITouch对象
现在了解关于UITouch的知识:
1、当用户用一根触摸屏幕时,会创建一个与手指相关联的UITouch对象
2、一根手指对应一个UITouch对象
UITouch的作用
1、保存着跟手指相关的信息,比如触摸的位置、时间、阶段
2、当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置
3、当手指离开屏幕时,系统会销毁相应的UITouch对象
提示:iPhone开发中,要避免使用双击事件。
UITouch的属性:
• 触摸产生时所处的窗口
• 触摸产生时所处的视图
• 短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
• 记录了触摸事件产生或变化时的时间,单位是秒
• 当前触摸事件所处的状态
UITouch常用方法:
1.返回值表示触摸在view上的位置
2.这里返回的位置是针对view的坐标系的(以view的左上角为原点(0, 0))
3.调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
1.该方法记录了前一个触摸点的位置
再来了解一下UIEvent的相关知识:
1、 每产生一个事件,就会产生一个UIEvent对象。
2、 UIEvent:称为事件对象,记录事件产生的时刻和类型。
常见属性:
1) 事件类型
2) 事件产生的时间
UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象
了解了UITouch和UIEvent,现在来说说触摸方法中的两个参数:
一次完整的触摸过程,会经历3个状态:
1、触摸开始:- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
2、触摸移动:- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
3、触摸结束:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
4、触摸取消(可能会经历):- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
4个触摸事件处理方法中,都有NSSet*touches和UIEvent *event两个参数
一次完整的触摸过程中,只会产生一个事件对象,4个触摸方法都是同一个event参数
如果两根手指同时触摸一个view,那么view只会调用一次touchesBegan:withEvent:方法,touches参数中装着2个UITouch对象
如果这两根手指一前一后分开触摸同一个view,那么view会分别调用2次touchesBegan:withEvent:方法,并且每次调用时的touches参数中只包含一个UITouch对象
根据touches中UITouch的个数可以判断出是单点触摸还是多点触摸
对UITouch和UIEvent有所了解,那下面我们就可以来讲解事件的产生和传递。
• 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中
• UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)
• 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步
• 找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理
1、touchesBegan…
2、touchesMoved…
3、touchedEnded…
观察下图:
说明:
1:控制器的view
2:控制器view的子控件
3:橙色2的子控件
4:蓝色3的子控件
触摸事件的传递是从父控件传递到子控件。
点击了绿色的view:
UIApplication -> UIWindow -> 白色 -> 绿色
点击了蓝色的view:
UIApplication -> UIWindow -> 白色 -> 橙色 -> 蓝色
点击了黄色的view:
UIApplication-> UIWindow -> 白色 -> 橙色 -> 蓝色 -> 黄色
如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件。
那么是如何找到这个最适合的控件来处理事件的呢?它的原则如下:
1、 判断自己是否能接收触摸事件;
2、 判断触摸点是否在自己身上;
3、 从后往前遍历子控件,重复前面的两个步骤;
4、 如果没有符合条件的子控件,那么自己就是最适合的view,自己处理事件
那么view有哪些情况是不能接收触摸事件的呢?
1、 不接收用户交互
userInteractionEnabled= NO
2、 隐藏
hidden = YES
3、 透明
alpha = 0.0 ~0.01
提示:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的
用户点击屏幕后产生的一个触摸事件,经过一些列的传递过程后,会找到最合适的视图控件来处理这个事件。找到最合适的视图控件后,就会调用控件的touches方法来作具体的事件处理
touchesBegan…
touchesMoved…
touchedEnded…
这些touches方法的默认做法(调用[super touches])是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理(响应者链条:由多个响应者对象通过事件传递连接在一起的链条。之前提到过响应者对象:能够接受并处理事件的对象(UIResponder))
引用官方文档的图:
响应者链的事件传递过程:
如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图
在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
如果window对象也不处理,则其将事件或消息传递给UIApplication对象
如果UIApplication也不能处理该事件或消息,则将其丢弃
大家可以简单记一下如何找到view的下一个响应者:
1) 如果当前view是控制器的view,那么控制器就是下一个响应者。
2) 如果当前view不是控制器的view,那么就父控件就是下一个响应者。
触摸事件的产生和传递就介绍到这里,大家主要记住和了解的就是事件的传递和响应者链条。
- (void)touchesBegan:(NSSet<UITouch*> *)touches withEvent:(UIEvent *)event - (void)touchesMoved:(NSSet<UITouch*> *)touches withEvent:(UIEvent *)event - (void)touchesEnded:(NSSet<UITouch*> *)touches withEvent:(UIEvent *)event
其实这些方法是触摸事件的方法,其中还有一个方法:
-(void)touchesCancelled:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event
还记得我们使用这些方法干了什么吗?
我们使用这些方法实现了手指在view 上的触摸事件处理。touchesBegan知道手指开始触摸的位置;touchesMoved知道手指移动过程中的位置;touchesEnded还知道手指触摸结束时候的位置,以此推断touchesCancelled方法可以告诉我们手指触摸被中止(如来电)时候的位置。
本章将介绍触摸事件的处理过程。
先了解一些和触摸事件有关的知识
1)用户在使用app的过程中,会产生各种各样的事件。iOS中的事件分为3大类型(引用官当文档的图片):
触摸事件 加速计事件 远程控制器事件
2)响应者对象:iOS中不是任何对象都能处理事件,只有继承自UIResponder的对象才能接受并处理事件,我们称之为“响应者对象”。
UIApplication、UIController、UIView都是继承自UIResponder,因此它们都是响应者对象,都能接受并处理事件。
3)UIResponder:为什么继承自UIResponder就能接受并处理事件呢。
因为UIResponder内部提供了以下方法来专门处理事件:
触摸事件方法:
- (void)touchesBegan:(NSSet<UITouch*> *)touches withEvent:(UIEvent *)event - (void)touchesMoved:(NSSet<UITouch*> *)touches withEvent:(UIEvent *)event - (void)touchesEnded:(NSSet<UITouch*> *)touches withEvent:(UIEvent *)event
-(void)touchesCancelled:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event
加速计事件方法:
- (void)motionBegan:(UIEventSubtype)motionwithEvent:(nullable UIEvent *)event - (void)motionEnded:(UIEventSubtype)motionwithEvent:(nullable UIEvent *)event - (void)motionCancelled:(UIEventSubtype)motionwithEvent:(nullable UIEvent *)event
远程控制事件方法
- (void)remoteControlReceivedWithEvent:(nullableUIEvent *)event
这里我们主要介绍触摸事件,所以对触摸事件方法做一下简单说明。拿之前自定义画板的例子。
画板是继承自UIView,UIView是继承自UIResponder。可以覆盖触摸方法来处理不同的事件:
一根或多根手指开始触摸view,系统会自动调用下面方法
-(void)touchesBegan:(NSSet<UITouch *>*)touches withEvent:(UIEvent *)event
一根或多根手指在view上移动,系统会自动调用下面方法(随着手指的移动,系统会一直调用这个方法)
-(void)touchesMoved:(NSSet<UITouch *>*)touches withEvent:(UIEvent *)event
一根或多根手指离开view,系统会自动调用下面方法(触摸事件结束)
-(void)touchesEnded:(NSSet<UITouch *>*)touches withEvent:(UIEvent *)event
一根或多根手指在view上的触摸被中止(如来电),系统会自动调用下面方法
-(void)touchesCancelled:(NSSet<UITouch*>*)toucheswithEvent:(UIEvent*)event
注意:touches中存放的都是UITouch对象
现在了解关于UITouch的知识:
1、当用户用一根触摸屏幕时,会创建一个与手指相关联的UITouch对象
2、一根手指对应一个UITouch对象
UITouch的作用
1、保存着跟手指相关的信息,比如触摸的位置、时间、阶段
2、当手指移动时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置
3、当手指离开屏幕时,系统会销毁相应的UITouch对象
提示:iPhone开发中,要避免使用双击事件。
UITouch的属性:
• 触摸产生时所处的窗口
@property(nonatomic,readonly,retain)UIWindow *window;
• 触摸产生时所处的视图
@property(nonatomic,readonly,retain)UIView *view;
• 短时间内点按屏幕的次数,可以根据tapCount判断单击、双击或更多的点击
@property(nonatomic,readonly)NSUInteger tapCount;
• 记录了触摸事件产生或变化时的时间,单位是秒
@property(nonatomic,readonly)NSTimeInterval timestamp;
• 当前触摸事件所处的状态
@property(nonatomic,readonly)UITouchPhase phase;
UITouch常用方法:
- (CGPoint)locationInView:(UIView *)view;
1.返回值表示触摸在view上的位置
2.这里返回的位置是针对view的坐标系的(以view的左上角为原点(0, 0))
3.调用时传入的view参数为nil的话,返回的是触摸点在UIWindow的位置
- (CGPoint)previousLocationInView:(UIView *)view;
1.该方法记录了前一个触摸点的位置
再来了解一下UIEvent的相关知识:
1、 每产生一个事件,就会产生一个UIEvent对象。
2、 UIEvent:称为事件对象,记录事件产生的时刻和类型。
常见属性:
1) 事件类型
@property(nonatomic,readonly)UIEventType type; @property(nonatomic,readonly)UIEventSubtype subtype;
2) 事件产生的时间
@property(nonatomic,readonly)NSTimeInterval timestamp;
UIEvent还提供了相应的方法可以获得在某个view上面的触摸对象
了解了UITouch和UIEvent,现在来说说触摸方法中的两个参数:
一次完整的触摸过程,会经历3个状态:
1、触摸开始:- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
2、触摸移动:- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
3、触摸结束:- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
4、触摸取消(可能会经历):- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
4个触摸事件处理方法中,都有NSSet*touches和UIEvent *event两个参数
一次完整的触摸过程中,只会产生一个事件对象,4个触摸方法都是同一个event参数
如果两根手指同时触摸一个view,那么view只会调用一次touchesBegan:withEvent:方法,touches参数中装着2个UITouch对象
如果这两根手指一前一后分开触摸同一个view,那么view会分别调用2次touchesBegan:withEvent:方法,并且每次调用时的touches参数中只包含一个UITouch对象
根据touches中UITouch的个数可以判断出是单点触摸还是多点触摸
对UITouch和UIEvent有所了解,那下面我们就可以来讲解事件的产生和传递。
• 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中
• UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)
• 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步
• 找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理
1、touchesBegan…
2、touchesMoved…
3、touchedEnded…
观察下图:
说明:
1:控制器的view
2:控制器view的子控件
3:橙色2的子控件
4:蓝色3的子控件
触摸事件的传递是从父控件传递到子控件。
点击了绿色的view:
UIApplication -> UIWindow -> 白色 -> 绿色
点击了蓝色的view:
UIApplication -> UIWindow -> 白色 -> 橙色 -> 蓝色
点击了黄色的view:
UIApplication-> UIWindow -> 白色 -> 橙色 -> 蓝色 -> 黄色
如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件。
那么是如何找到这个最适合的控件来处理事件的呢?它的原则如下:
1、 判断自己是否能接收触摸事件;
2、 判断触摸点是否在自己身上;
3、 从后往前遍历子控件,重复前面的两个步骤;
4、 如果没有符合条件的子控件,那么自己就是最适合的view,自己处理事件
那么view有哪些情况是不能接收触摸事件的呢?
1、 不接收用户交互
userInteractionEnabled= NO
2、 隐藏
hidden = YES
3、 透明
alpha = 0.0 ~0.01
提示:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的
用户点击屏幕后产生的一个触摸事件,经过一些列的传递过程后,会找到最合适的视图控件来处理这个事件。找到最合适的视图控件后,就会调用控件的touches方法来作具体的事件处理
touchesBegan…
touchesMoved…
touchedEnded…
这些touches方法的默认做法(调用[super touches])是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理(响应者链条:由多个响应者对象通过事件传递连接在一起的链条。之前提到过响应者对象:能够接受并处理事件的对象(UIResponder))
引用官方文档的图:
响应者链的事件传递过程:
如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图
在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
如果window对象也不处理,则其将事件或消息传递给UIApplication对象
如果UIApplication也不能处理该事件或消息,则将其丢弃
大家可以简单记一下如何找到view的下一个响应者:
1) 如果当前view是控制器的view,那么控制器就是下一个响应者。
2) 如果当前view不是控制器的view,那么就父控件就是下一个响应者。
触摸事件的产生和传递就介绍到这里,大家主要记住和了解的就是事件的传递和响应者链条。
相关文章推荐
- IOS回调
- iOS 9 中的变化汇总
- iOS跳转系统设置界面
- 用CocoaPods做iOS程序的依赖管理
- iOS 代码块在程序中只执行一次
- iOS证书说明和发布内购流程整理
- iOS 8 新特性总结
- iOS_导入libxml2.2框架后,找不到<libxml/tree.h>的解决办法
- iOS开发多线程篇—GCD介绍
- iOSCocoaPods Updating local specs repositories
- IOS-35-NSAssert的使用
- ios的手势的添加
- iOS开发~CocoaPods使用详细说明
- iOS时间和时间戳之间的转化
- IOS-34-单例设计模式详解
- iOS 手势操作:拖动、捏合、旋转、点按、长按、轻扫、自定义
- IOS接口解析(GET请求)
- NSRegularExpression iOS自带的正则表达式
- IOS .pch 文件详解
- iOS - ABPeoplePickerNavigationController 获取手机通讯录信息