美文网首页
iOS中Touches,Presses,and Gestures

iOS中Touches,Presses,and Gestures

作者: 琦思妙想君 | 来源:发表于2018-01-16 17:10 被阅读52次

最近把这个小系列的文档刷了一遍,结合另外一篇 Understanding Event Handling, Responders, and the Responder Chain,对 iOS 中事件的传递和处理有了比较全面的理解。

核心类

  • UIResponder
  • UIEvent
  • UITouch
  • UIPress
  • UIGestureRecognizer

其中 UIResponder 和 UIEvent 是事件传递过程用到的类,UITouch,UIPress 和 UIGestureRecognizer 是事件处理过程用到的类。

UIKit 在收到各种事件后封装成 UIEvent 并通过 UIResponder 进行传递。

响应链与事件传递

苹果在事件传递中采用了一个单向链表的响应链设计,即事件在链表中向后传递,直到找到一个能响应该事件的响应者。事件即 UIEvent,响应者即 UIResponder。UIResponder 的 nextResponder 即是链表指向下一个响应者的指针。

响应链的起始节点就是 firstResponder,各种事件寻找 firstResponder 的方法不同。

Touch events
The first responder is the view in which the touch occurred.

Press events
The first responder is the responder that has focus.

Shake-motion events
The first responder is the object that you (or UIKit) designate as the first responder.

Remote-control events
The first responder is the object that you (or UIKit) designate as the first responder.

Editing menu messages
The first responder is the object that you (or UIKit) designate as the first responder.

Touch 事件是用户在屏幕上点击触发的事件,这是最多的一类事件,苹果提供的处理和追踪方法也最丰富。

Press 事件是外接设备的物理按键产生的事件,比如苹果外接的游戏手柄,它的很多处理方法都和 Touch 事件一致,是在 iOS 9 中增加的特性,不做游戏开发基本也用不上。

Touch 事件是如何寻找 firstResponder 的?

苹果通过 hitTest 方法和 pointInside 方法在视图树中从上到下一层一层测试到底点击事件应该由哪个响应者响应。找到的这个响应者就是 touch 事件的 firstResponder。

事件处理

UIKit 将用户点击封装成 UITouch,然后装载到 UIEvent 中通过 touches 系列方法回调给 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 *> *)touches withEvent:(UIEvent *)event;

我们可以覆盖这几个方法来处理 touch 事件,UIView 是继承自 UIResponder 的,所以我们常用的 UI 组件都包含这几个方法。

UIEvent

这个类的主要作用是装载 UITouch 对象,并提供一些查询和追踪方法。

UITouch

这个类包含了用户点击的各种信息,包括位置、次数、时间、力度、角度等。

Gesture

苹果提供的 UIGestureRecognizer 是一组强大的设计,提供了很多功能,让我们能将用户的动作按特征抽象成一个手势,实现了手势的识别和处理的解耦。

Gesture 中也有 touches 系列方法,使用方法和 UIResponder 类似。我们可以在这里追踪 touch 的特征并解读成各种手势。我们可以使用自定义的 Gesture 来替代 UIResponder 的 touch 识别逻辑,封装性和复用性更好。

Gesture 和响应链的关系

Gesture 是被添加到 view 上的,它不参与响应链的传递,但是它会先于 view 对事件进行响应。它还提供了一组方法来控制 touch 是否被传递给相应的 view。

自定义 Gesture

自定义 Gesture 十分强大,我们需要注意 Gesture 有两种类型:离散手势和连续手势。不同的类型在识别过程中对 Gesture 状态的改变路径是不同的。

实现自定义 Gesture 需要做三件事:

  • 在 touches 系列方法中解析用户动作特征
  • 根据解析结果设置相应的状态
  • 清理状态和数据值

多个手势的叠加

苹果提供了许多方法来帮助我们处理多个手势同时存在的情况:

  • 多个手势同时分别进行识别
  • 一个手势要在另一个手势识别失败之后才开始识别

实话说苹果在此处提供的方法有些凌乱,UIGestureRecognizerDelegate 和 UIGestureRecognizer 中存在许多相同作用的方法。我猜想大概是为了方便我们使用,在使用系统定义的 Gesture 时可以使用 delegate,在自定义的 Gesture 时可以覆盖 UIGestureRecognizer 中的方法。

更高精度的 touch 追踪

UIKit 处理 touch 事件的频率是 60Hz,苹果在 iOS 9 之后的版本中添加了一些特性让我们可以获取更高精度的 touch,主要是因为出现了采样频率更高的设备,比如 Apple Pencil。

touch 预测

苹果在 iOS 9 中还做了一些优化来减少追踪 touch 时的卡顿,UIEvent 中提供了对之后 touch 事件的预测,具体的可以看文档。

相关文章

网友评论

      本文标题:iOS中Touches,Presses,and Gestures

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