概述:
每当用户操作iOS设备,iOS系统就会解析用户的操作行为,并将这些操作系统封装成事件发送给相应的App,这些事件源包括以下四种:
  • Touch Event
  • Motion Event
  • Remote Control Event
  • Presses Event
目录:
  • Gesture Recognizers
  • Event Delivery: The Responder Chain
  • Multitouch Events
  • Motion Events
  • Remote Control Events

Gesture Recognizers
UIKit Makes it Easy for Your App to Detect Gestures:
原本手指在屏幕的触控事件全都是通过UIView的范畴(非正式协议)事件来监听:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
识别成功会调用END,识别失败调用cancel,如在view上还有手势识别器的情况下,当手势识别器识别成功,touch非正式协议就会调用cacenl。
但UIKIT直接将再进行封装成各种UIGestureRecognizer用于识别一些通用的手势,甚至直接将手势应用于UIControl的子类,如UIButton、UISlider等,让其能直接相应与自身图形相关的触摸事件。这些手势识别器都是利用target-Action实现的,均将手势与事件直接一一对应。当然我们也可以自己定义自己所需的手势。
Target-Action机制与响应链机制的关系:
Target-Action,其实就是send action message to target when action happen,所以就是一种将事件与响应对象一一绑定的机制。而手势识别器就是应用了该机制,所以在初始化的时候会要求参入target与SEL两个关键参数以实现绑定,达到若某事件发生,就可以调用target-SEL实现效果。
而响应链机制就是iOS中事件传递的机制,它与Target-Action的关系是,当Target-Action中的SEL为nil,也就是对象无法处理事件时,事件就会沿着响应者链条回传。
Built-in Gesture Recognizers common Gestures:
UIKit定义的通用手势识别器:
  • UITapGestureRecognizer(Tapping,any numbers of taps,点击)
  • UIPinchGestureRecognizer(Pinching in and out,for zooming a view,捏)
  • UIPanGestureRecognizer(panning or dragging,拖动)
  • UISwipeGestureRecognizer:(swiping,in any direction,滑动)
  • UIRotationGestureRecognizer(rotating,fingers moving in opposite directions,旋转)
  • UILongPressGestureRecognizer(Long press,also known as “touch and hold”,长按)
Discrete and Continuous Gesture:
手势也分有离散手势与连续手势两种,离散手势如Tap Gesture,只会发送一次Action message。但连续手续,如Pinch Gesture就不一样,它是在手势缩放的整个过程都会连续发送action message。
Responding to Events with Gesture Recognizer:
添加一个手势识别器需要做的三件事:
  1. 创建手势识别器,并绑定Target、Action,或者指定特殊的参数,如numberOfTapsRequired
  2. 将手势识别器添加到View中
  3. 实现手势识别器的Action
响应离散手势与连续手势的区别:
  • 离散手势:只处理一个Action message事件。
  • 连续手势:需要连续处理多个Action message事件。而且在连续手势中还得判断以下几个状态,针对不同的状态进行不同的处理:
    • UIGestureRecognizerStatePossible
    • UIGestureRecognizerStateBegan
    • UIGestureRecognizerStateChanged
    • UIGestureRecognizerStateEnded
    • UIGestureRecognizerStateFailed
所以手势识别的过程实际上就是一个状态机在不同的状态下切换的过程,而且每一次状态的切换都伴随着一个action send to target的过程,如下图所示:
PS:其中Recognized状态已经被End状态取代。
Defining How Gesture Recognizers Interact:
UIView通过一个NSArray属性gestureRecognizers来管理手势识别器,所以一个View也可以同时具有数个手势识别器,可以通过addGestureRecognizer与removeGestureRecognizer来进行添加与移除。
在默认情况下,当一个UIView同时包含若干去手势识别器,这些识别器收到touch的顺序每次都是随机的,但我们可以通过重写或者UIGestureRecognizerDelegate来实现以下的效果:
  1. 制定一个手势识别必须要先执行与另一个手势之前
  2. 允许同时手势进行分析执行
  3. 阻止一个手势识别器去分析touch
通过重写UIGestureRecognizer的子类方法或者实现delegate可以实现以上效果,而且在某些特殊场合十分重要。
如一个界面添加了swipes and pans手势识别器,这两个手势有比较多的共同点,默认模式容易识别错,所以需要特殊处理。
UIKit中UIControl的子类,不少都是已经封装好特定的手势识别器的了,为了不造成重叠,UIKIT默认若开发者继续添加了相同的手势识别器的,会旁路掉默认的手势识别器。包括以下场景:
  1. 添加Tap到UIButton、UISwitch、UIStepper、UISegmentedControl、UIpageControl
  2. 添加swipe到UISlider
  3. 添加Pan到UISwitch
Gesture Recognizer Interpret Raw Touch Events
手势识别器的原理本质上就是通过UIView通过范畴实现的非正式协议方法来实现的,如下图:
  • touchesBegan:withEvent: method when one or more fingers touch down on the screen.
  • touchesMoved:withEvent: method when one or more fingers move.
  • touchesEnded:withEvent: method when one or more fingers lift up from the screen.
  • touchesCancelled:withEvent: method when the touch sequence is canceled by a system event, such as an incoming phone call.
通过重写以上方法即可监听用户在View的触摸行为,其中有两个很重要的参数,UITouch与UIEvent,当iOS在有交互时间产生,UIEvent就会在响应链中传递,
而UIEvent有有两个重要枚举 UIEventType、 UIEventSubtype。
其中UIEventType的结构如下:
typedef NS_ENUM(NSInteger, UIEventType) {
    UIEventTypeTouches,
    UIEventTypeMotion,
    UIEventTypeRemoteControl,
    UIEventTypePresses NS_ENUM_AVAILABLE_IOS(9_0),
};
UIEventSubtype的结构如下:
typedef NS_ENUM(NSInteger, UIEventSubtype) {
    // available in iPhone OS 3.0
    UIEventSubtypeNone                              = 0,
   
    // for UIEventTypeMotion, available in iPhone OS 3.0
    UIEventSubtypeMotionShake                       = 1,
   
    // for UIEventTypeRemoteControl, available in iOS 4.0
    UIEventSubtypeRemoteControlPlay                 = 100,
    UIEventSubtypeRemoteControlPause                = 101,
    UIEventSubtypeRemoteControlStop                 = 102,
    UIEventSubtypeRemoteControlTogglePlayPause      = 103,
    UIEventSubtypeRemoteControlNextTrack            = 104,
    UIEventSubtypeRemoteControlPreviousTrack        = 105,
    UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
    UIEventSubtypeRemoteControlEndSeekingBackward   = 107,
    UIEventSubtypeRemoteControlBeginSeekingForward  = 108,
    UIEventSubtypeRemoteControlEndSeekingForward    = 109,
};
从上面的数据结构可以,其实UITouch是封装在UIEvent中的,但这里非正式协议中的方法为了开发者方便把它单独抽离出来成为一个参数。
Regulating the Delivery of Touch to Views
默认的touch event时间传递的顺序如上图所示,很明显每个action是先经过Gesture recognize再到View的。若Gesture recognize先于View完成手势识别,那么view中的touch event分析就会进入cancel状态。
可以通过设置UIGestureRecognizer的delaysTouchesBegin、delaysTouchEnded属性来改变默认的事件传递规则,如下:
  • delaysTouchesBegin(default:NO):禁止信息传递到view
  • delaysTouchEnded(default:YES):手势识别器延迟结束,等待touch非正式协议完成识别。
手势识别器可以通过调用 ignoreTouch:forEvent:来忽略特殊的事件。
Creating a Custom Gesture Recognizer
可以通过继承UIGestureRecognizer并重写以下基础方法,即可实现自定义的手势识别器:
- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

Event Delivery: The Responder Chain
当用户因操作而产生事件时,UIKIT就会创建一个UIEvent包含处理事件所需的信息,然后系统把这个事件放置到当前激活的App的时间队列里面。然后处于激活状态的UIApplication对象从任务队列中获取UIEvent并然后将其传递到key window,然后通过响应链找到能处理该事件的对象。
对于不同的UIEvent的传递方式略有不同:
  • Touch event:通过hit-test机制,找到hit-testView,若hit-testView无法处理事件,则沿着响应者链条找寻能处理事件的对象。
  • Motion and remote control event:window对象直接把事件传递给第一响应者。
Hit-Testing return the view where a touch occurred:
hit-test机制寻找hit-test view的例子:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
hit-test机制的核心方法的默认实现如下所示:
  1. 调用 pointInside:withEvent:判断屏幕点击的点是否在本view范围内,是返回YES,不是返回NO
  2. 若返回YES,则递归subviews,并调用其hit-test方法,若返回NO,则返回nil
  3. 最终有效返回的View就是hit-test view
The responder chain is made up of responder objects
所有继承于UIResponer的对象都可以成为响应者,均具备响应处理事件的能力,而这些对象组成的链条,称为响应者链条。
响应者链条由第一响应者开始,到UIApplication结束。
第一响应者就是首先接收事件的对象,对象可以通过以下方法主动成为第一响应者:
  • 重写canBecomeFirstResponder方法,并返回YES
  • 调用becomFirstResponder方法。
Event不是唯一依赖响应者链条的,响应者链条常用于以下场景:
  • Touch Events:
  • Motion Event:
  • Remote Control event
  • action message
  • editing-meun message
  • text editing
响应者链条的结构:
首先每个事件都会有自己对应的响应者链条,所以响应者链条是动态生成的。
对应Touch Event:由hit-test机制生成。
对于Motion、Remote Event:由程序设定,设定谁了first responder,然后若first responder无法响应,然后就是按照响应者链条回传,就是first responder——》。。。——》application的过程,中间的传递规律如下图。
The responder chain follows a specific Delivery
响应者链条是专门用于传递用户与设备交互而产生的事件,而别的系统事件是通过的别的方式来传递的,这里得区分。
响应链的传递规则图:

Multitouch Events
Creating a SubClass of UIResponder
implementing the Touch-event Handing method in your subclass
Tracking the phase and location of a touch event
Retrieving and Querying Touch Objects
Handling Tap Gestures
Handling Swipe and Drag Gestures
Handling a Complex Multitouch Sequence
Specifying Custom Touch Event Behavior
Intercepting Touches by Overriding Hit-Testing
Forwarding Touch Events
Best Practices for Handling Multitouch Events

Motion Events
当用设备移动、摇晃、倾斜,就会生成motion events事件。这类型的事件大多产生于iOS的硬件传感器,如:
  • 加速计:测量设备各个方向上的加速度
  • 陀螺仪:测量设备各个方向上的旋转速率
  • GPS:测量位置
Getting the Current Device Orientation with UIDevice
若想获取设备的方向,可以直接通过UIDevice实现。实例代码如下:
-(void) viewDidLoad {
// Request to turn on accelerometer and begin receiving accelerometer events
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)orientationChanged:(NSNotification *)notification {
// Respond to changes in device orientation
}
-(void) viewDidDisappear {
// Request to stop receiving accelerometer events and turn off accelerometer
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}
PS:就是通过通知的方式获取设备的方向。

Detecting Shake-Motion Events with UIEvent
由于motion都是直接发给第一响应者,若第一响应者无法处理,则继续在响应者链条回传。
若设置了第一响应者,还得实现以下方法才能完成得到相应的数据,实现功能。
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event

Setting and Checking Required Hardware Capabilities for Motion Events
略。

Capturing Device Movement with Core Motion
捕抓motion的核心数据的教程。


Remote Control Events
能实现用外部设备控制多媒体APP,又或者在锁屏的情况下还能控制多媒体。使用命令模式实现。
Preparing Your App for Remote Control Events
能接收远程控制时间,得满足以下条件:
  1. 为各种Action注册handle,MPRemoteCommandCenter 能实现各种事件的注册。
  2. app要处于正在播放的状态。
Handling Remote Control Events
为特定事件添加handle的代码:
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.playCommand addTargetUsingBlock:^(MPRemoteCommandEvent *event) {
// Begin playing the current track.
[[MyPlayer sharedPlayer] play];
}

Providing Now Playing Information
通过 MPNowPlayingInfoCenter 对象获取播放信息。

Testing Remote Control Events on a Device

Event Handing guide for iOS相关推荐

  1. Event Handling Guide for iOS——由触摸事件传递想到的

    先帖官方文档地址 https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlin ...

  2. View Programming Guide for iOS官方文档翻译一

    版权声明:本文为博主原创文章,转载请声明出处,谢谢! 本文档的官方英文原版地址 关于窗口和视图 在iOS中,您可以使用窗口(windows)和视图(views)在屏幕上显示APP的内容. 窗口(Win ...

  3. xx.xib: error: Illegal Configuration: Safe Area Layout Guide before iOS 9.0报错问题解决

    之前是用xcode8.3.3创建的工程最近升级到Xcode9.0 遇见了这个问题 在Xcode 9.0以上 新建xib文件会报错 xx.xib: error: Illegal Configuratio ...

  4. iOS---------- Safe Area Layout Guide before iOS 9.0

    如果你们的项目不做iOS9以下支持就打开main.storyboard    去除Use safe Area Layout 如果不考虑iOS9以下支持就按照下面的步骤 选中控制器,右边面板的Build ...

  5. iOS订阅测试终极指南The Ultimate Guide to iOS Subscription Testing

    订阅测试如何测试呢?平时遇到的都是消耗型商品,没有持续性,买完就完了,而订阅型是一个持续时间段,这个时间内有很多故事发生,测试起来相对也是复杂的多.找到一篇文章,参考下: 找到并修复错误,这样你就不会 ...

  6. View Programming Guide for IOS:Views笔记

    1.执行画图代码: "当前绘图上下文"只在执行视图的drawRect方法期间才有效.UIKit有可能会在后续调用drawRect方法时声称一个新的视图上下文,所以你不能试图去缓存这 ...

  7. iOS 实战开发课程笔记

    iOS 实战开发课程笔记 本贴旨在作为对极客班 <iOS 开发实战>第五期期课程视频重新学习的笔记. 目标是建立一个比较完整的 iOS 开发知识点框架以及快速手册. 对各个内容的详细研究会 ...

  8. iOS 4层结构(iOS技术概要)—— Cocoa Touch 层(一)

            苹果公司的iOS平台强力推动了iOS开发,引来了不少人从事iOS开发,也成就了一批一批的开发者,如果你是新手,请把本文作为iOS技术一览,便于你对iOS开发有个粗略的认识:如果你已经是 ...

  9. iOS iPhone官方参考资料明细

    官方的门户站点 Refernce Library Mac OS X Refernce Library http://developer.apple.com/library/mac/navigation ...

  10. 深度解析~iOS应用程序~生命周期

    摘要:iOS应用程序一般都是由自己编写的代码和系统框架组成,系统框架提供一些基本infrastructure给App来运行,而开发者则自己编写代码定制App的外观和行为,了解iOS Infrastru ...

最新文章

  1. 对ie6、ie7、ff兼容性的详细css hack介绍
  2. 正则学习(2)--- 简单匹配原理
  3. 指针系统学习7-返回指针值的函数
  4. 对搜狗输入法的个人评价
  5. VSCode从下载到配置Ubuntu系统
  6. jsf标签_多个动态包含一个JSF标签
  7. web开发要学多久,HTML表格标签,薪资翻倍
  8. SpringMVC redirect中文乱码问题
  9. python60行绘图程序_不敢相信,60行python代码就写出了贪吃蛇游戏
  10. intel SPR新特性CXL
  11. HtmlHelper、TagHelper、局部视图、视图组件
  12. ICNet: Intra-saliency Correlation Network for Co-Saliency Detection
  13. 网易互娱2022校园招聘在线笔试-游戏研发工程师(第一批)
  14. 隐私政策说明 - 掌上软考答题速记系统
  15. git push时rejected,解决non-fast-forward errors的办法
  16. Java 的三种技术架构
  17. 关于微新分享PC微信端成功,手机微信失败
  18. Android 之 打开相机 打开相册
  19. oracle ebs版本查看,Oracle EBS R12 - 如何取得EBS某个文件的版本号
  20. Java 使用正则表达式匹配淘口令

热门文章

  1. matlab 怎么求直线斜率,matlab中如何求近似(不平滑)直线的斜率
  2. 程序员如何改善精神内耗?
  3. 领导力21法则 非常不错
  4. ES7.16.2基础操作之slop查询(三)
  5. failover机制
  6. LoRaWan 硬件和信道特点 TDMA的MAC协议优势
  7. Excel表格之道 学习笔记(四)
  8. 代码随想录第八天 LeetCode 344、541、剑指Offer 05、151、剑指Offer58 (字符串)
  9. qcon_从QCon伦敦2009中学到的主要知识点和教训
  10. 如何彻底禁用谷歌Chrome更新