iOS事件传递

作者: 芮小妹儿很闲 | 来源:发表于2018-05-31 10:20 被阅读16次

iOS中事件分为

  • 触摸事件
  • 加速计事件
  • 远程控制事件

响应者对象

能够接收并处理事件的对象,必须是UIResponder的子类。比如:UIApplicationUIWindowUIView等。

UIResponder处理事件的几种方法

1、触摸事件

// 一根或者多根手指开始触摸
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
// 一根或者多根手机在屏幕上移动,只要移动就会触发
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
// 一根或者多根手指离开屏幕
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
// 结束触摸前,由系统强制退出或者来电,事件会被取消
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
// 预估触摸特性,当从边缘进入,系统不知道当前触摸特性,会被调用下列方法
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches;

2、加速计事件

// 开始动起来
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
// 运动结束
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
// 运动被打断,取消
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

3、远程控制事件

- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

UITouch

  • 触摸事件中,touches中存放的是UITouch对象,一根手指对应一个UITouch对象
  • 触摸开始,系统会创建手指对应的UITouch对象,随着手指移动,UITouch对象会随着更新,触摸事件结束,系统会销毁这个UITouch对象
1、属性
// 触摸产生时对应触摸的窗口
@property(nullable,nonatomic,readonly,strong) UIWindow *window;
// 触摸产生时对应的触摸视图
@property(nullable,nonatomic,readonly,strong) UIView *view;
// 触摸事件产生或者变化的时间(单位秒)
@property(nonatomic,readonly) NSTimeInterval timestamp;
// 当前触摸事件的状态(开始:Began、移动:Moved、静止:Stationary、结束:Ended、取消Cancelled)
@property(nonatomic,readonly) UITouchPhase phase;
// 短时间的触摸次数,据此判断是几根手指触摸,双击、单击或者其他更多
@property(nonatomic,readonly) NSUInteger tapCount;
// 触摸手势组
@property(nullable,nonatomic,readonly,copy)   NSArray <UIGestureRecognizer *> *gestureRecognizers;
# pragma mark - iOS8新增属性
// 触摸的主半径
@property(nonatomic,readonly) CGFloat majorRadius;
// 触摸主半径的公差
@property(nonatomic,readonly) CGFloat majorRadiusTolerance;
# pragma mark - iOS9新增属性
// 触摸类型(直接手指触摸:Direct、间接触摸:Indirect、触摸笔触摸:Stylus)
@property(nonatomic,readonly) UITouchType type;
// 触摸力度,其中1.0表示平均力压值
@property(nonatomic,readonly) CGFloat force;
// 能触摸的最大力度
@property(nonatomic,readonly) CGFloat maximumPossibleForce;
// 高角度,仅适用于用触摸笔触摸类型。0:触摸笔平行于平面;M_PI/2:触摸笔垂直于平面
@property(nonatomic,readonly) CGFloat altitudeAngle;
// 预估更新索引,可以让更新的触摸对象与原对象进行关联,当前触摸对象的触摸特性变化,该值就会加一
@property(nonatomic,readonly) NSNumber * _Nullable estimationUpdateIndex;
// 预估属性,当前触摸对象的预估触摸特性(力度:Force、方位角:Azimuth、高度:Altitude、位置:Location)
@property(nonatomic,readonly) UITouchProperties estimatedProperties;
// 预期将要更新的特性,如果没有更新,则当前值为最终预估值,用于从边缘进入时系统开始无法获得准确的touches值
@property(nonatomic,readonly) UITouchProperties estimatedPropertiesExpectingUpdates;
2、方法
// 返回触摸在view上的坐标位置(以view左上角原点(0, 0)为准),若传入的view = nil,则返回触摸点在window上的位置
- (CGPoint)locationInView:(nullable UIView *)view;
// 同上,这个方法记录了上一个触摸点的位置
- (CGPoint)previousLocationInView:(nullable UIView *)view;
# pragma mark - iOS9新增方法
// 精准的返回触摸在view上的坐标位置
- (CGPoint)preciseLocationInView:(nullable UIView *)view;
// 精准的返回上一个在view上的触摸位置
- (CGPoint)precisePreviousLocationInView:(nullable UIView *)view;
// 返回触摸在view上的方位角(仅适用于触摸笔触摸事件)
- (CGFloat)azimuthAngleInView:(nullable UIView *)view;
// 返回触摸在view上的指向方向角的单位向量(仅适用于触摸笔触摸事件)
- (CGVector)azimuthUnitVectorInView:(nullable UIView *)view;

UIEvent

  • 每产生一个事件就会产生一个UIEvent对象
  • UIEvent对象记录了事件的产生时刻和类型
1、属性
// 事件类型(Touches:点击、Motion:加速计、RemoteControl:远程控制、Presses:按压)
@property(nonatomic,readonly) UIEventType type;
/**
同一事件类型的具体事件

None:type是触摸
MotionShake:type是加速计

== 剩下是针对远程控制事件类型 ==
RemoteControlPlay:播放
RemoteControlPause:暂停
RemoteControlStop:停止
RemoteControlTogglePlayPause:切换播放暂停
RemoteControlNextTrack:下一曲
RemoteControlPreviousTrack:上一曲
RemoteControlBeginSeekingBackward:开始往后寻找(开始快退)
RemoteControlEndSeekingBackward:结束向后寻找(结束快退)
RemoteControlBeginSeekingForward:开始向前寻找(开始快进)
RemoteControlEndSeekingForward:结束向前寻找(结束快进)
*/ 
@property(nonatomic,readonly) UIEventSubtype subtype;
// 事件产生的时间
@property(nonatomic,readonly) NSTimeInterval timestamp;
// 事件中产生的所有触摸点
@property(nonatomic, readonly, nullable) NSSet <UITouch *> *allTouches;
2、方法
// 返回在窗口上的所有触摸点
- (nullable NSSet <UITouch *> *)touchesForWindow:(UIWindow *)window;
// 返回在当前视图上的所有触摸点
- (nullable NSSet <UITouch *> *)touchesForView:(UIView *)view;
// 返回事件中手势的触摸点
- (nullable NSSet <UITouch *> *)touchesForGestureRecognizer:(UIGestureRecognizer *)gesture
# pragma mark - iOS9新增方法
// 将丢失的触摸点放在一个数组中返回(手机扫描渲染是每秒60帧,会出现绘画延迟,所以有些触摸点会丢失,下列方法是针对这种情况的优化)
- (nullable NSArray <UITouch *> *)coalescedTouchesForTouch:(UITouch *)touch;
// 预测的一组触摸点位置,但是不定和实际触摸点一样,所以是预估值
- (nullable NSArray <UITouch *> *)predictedTouchesForTouch:(UITouch *)touch;

不能接收事件情况:

  • 不能接收用户交互,self.userInteractionEnabled = NO
  • 被隐藏,self.hidden = YES
  • 透明度小于0.01,self.alpha < 0.01
  • 如果父控件不能接收触摸事件,那么子控件也将不能接收

触摸事件中事件的产生和传递

1、事件发生后,系统会将事件加入到UIApplication管理的队列中
2、UIApplication遵循先进先出的原则,将队列中先进的事件发送给主窗口(keyWindow)
3、主窗口会在视图层级中找到一个合适的view来接收和处理事件
4、找到合适的view后,会调用视图的touches方法来具体处理事件

具体寻找合适的view

1、先判断view是否能接收触摸事件
2、触摸点是否在view身上
3、在子控件数组中从后向前遍历子控件,然后重复上面两步,找到则返回合适的子控件
4、没找到合适的子控件,则自己就是合适处理的

选出最佳view方法

// 事件一传递给控件,就会调用下列方法,返回最合适接收事件的UIView
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
// 默认值是 YES,返回触摸点是否在调用者身上
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;

事件传递详细过程

1、触摸事件产生和传递后,找到最佳接收和处理事件的view
2、插入说明:响应者链条由事件响应者组成
3、如果最佳视图调用了[super touches...],则事件由下往上顺着响应者链传递上去
4、接着就会调用上一个响应者的touches...方法
5、如果上一个响应者不能响应,则传递给上上一个响应者
6、如果传递到UIApplication还是不能处理,那这个时间就会被废弃

判断上一个响应者

  • 如果当前视图是视图控制器的view,则上一个响应者是该视图的视图控制器
  • 如果当前视图没有视图控制器,则上一个响应者是该视图的父视图

实例

实例图片

所属关系:
self.view:子控件灰色
灰色:子控件先添加红色,后添加绿色
绿色:子控件先添加橘色,后添加白色

符合:满足可接收事件条件,自身能接收事件,触摸点在自己身上
否:不能接收事件

点击红色:UIApplication -> UIWindow -> 灰色(符合)-> 查询灰色子控件(红色、绿色)-> 绿色(触摸点不在身上,否)-> 红色(符合)
点击白色:UIApplication -> UIWindow -> 灰色(符合)-> 查询灰色子控件(红色、绿色)-> 绿色(符合)-> 查询绿色子控件(白色、橘色)-> 橘色(触摸点不在身上,否)-> 白色(符合)
点击橘色:UIApplication -> UIWindow -> 灰色(符合)-> 查询灰色子控件(红色、绿色)-> 绿色(符合)-> 查询绿色子控件(白色、橘色)-> 橘色(符合)

具体演示demo,请点击这里

相关文章

  • iOS 响应链

    iOS开发 - 事件传递响应链iOS 响应者链,事件的传递事件传递之响应链Cocoa Touch事件处理流程--响...

  • 深入浅出iOS事件机制

    深入浅出iOS事件机制事件传递:响应链事件传递响应链

  • iOS事件,原来如此

    精简地说:iOS事件分为传递和响应两个部分。 事件传递(建立传递链): iOS系统检测到手指触摸(Touch)操作...

  • 初识iOS事情处理机制

    参考:史上最详细的iOS之事件的传递和响应机制-原理篇iOS触摸事件全家桶史上最详细的iOS之事件的传递和响应机制...

  • iOS响应者链

    参考好文 iOS开发-事件传递响应链,用运行时分析 iOS事件传递:响应者链[译] http://www.jian...

  • 事件层级原理 响应链

    iOS事件 运动事件,远程控制事件、触摸事件 触摸事件 事件传递的顺序 当点击红色的时候 打印为 事件传递的方法 ...

  • iOS 触摸事件与响应理解

    参考文章: iOS触摸事件的流动 iOS触摸事件的传递与响应 UIViewController UIAppli...

  • iOS之事件的传递和响应机制

    iOS之事件的传递和响应机制

  • ios 事件传递和响应

    史上最详细的iOS之事件的传递和响应机制-原理篇iOS触摸事件传递响应之被忽视的手势识别器工作原理手势事件中can...

  • 二、事件传递链和响应者链

    iOS触摸事件详解iOS开发-事件传递响应链 响应者链 UIResponser包括了各种Touch message...

网友评论

    本文标题:iOS事件传递

    本文链接:https://www.haomeiwen.com/subject/cqrxsftx.html