iOS事件传递

时间:2018-05-11 01:07:49来源:杰瑞文章网点击:作文字数:500字
转至(https://www.oschina.net/question/1777276_2132459)前言无论是Android,还是IOS,都是事件驱动的操作系统,事件是操作系统的灵魂。却很少有人能够理清楚事件在操作系统内部是如何进行传递处理的。这篇文章将深入探讨iOS系统事件,阐述事件是如何在iOS系统内部进行传递并处理的,希望这篇文章能够对你有所帮助。代码说明本文将使用Objective-C语言进行编码,使用Cocoapods作依赖管理。同时,使用了一个非常优秀的自动布局库PureLayout。PureLayout是拥有非常优秀的自动布局API,支持iOS和OS X双系统,强烈推荐大家使用。基本原理事件的分类iOS系统将事件分为三类:Multitouch EventsMotion EventsRemote Control EventsMultitouch Events: 所谓的多点触摸事件,非常好理解,即用户触摸屏幕交互产生的事件类型。Motion Events: 所谓的移动事件。是指用户在摇晃,移动和倾斜手机的时候产生的事件成为移动事件。这类事件依赖于iPhone手机里面的加速计,陀螺仪等传感器。Remote Control Events:所谓的远程控制事件。这个事件从名称上面看,不太好理解。但其实,这个事件指的是用户在操作多媒体的时候产生的事件。比如,播放音乐、视频等。仔细分析这三类事件,Multitouch Events有明确的触摸视图,UIKit框架的View对象可以明确获取到当前点击的视图对象以及坐标。然后,对触摸视图做出相应的响应。而Motion Events和Remote Control Events却没有一个明确的交互界面的概念。iOS系统为了支持对这类事件的响应,提出了Responder的概念。关于Responder,我们后面再来探讨。鉴于系统对这三类事件处理的区别,我们将这三类事件区分为两类:Multitouch Events有明确的交互界面,可以获取到当前点击的视图组件,并作出相应的响应。Motion Events and Remote Control Events没有明确的交互界面,依赖于Responder对事件作出相应的响应Continue首先,让我们来了解一下Responder的概念,什么是Responder,怎样才能成为Responder,Responder又是如何对事件作出响应的。About Responder1) 什么是Responder?Responder是UIKit框架封装的一个对象类型,它可以响应并处理事件。所有Responder对象的基类都是UIResponder,下面我们来通过一张类图看看哪些对象具有Responder特性 图-1从上图可以看出,UIApplication、UIViewController和UIView都是UIResponder对象,都具有对事件进行响应,处理的能力再来看看UIResponder类里面的一些方法和属性- (UIResponder)nextResponder;- (BOOL)canBecomeFirstResponder;// default is NO- (BOOL)becomeFirstResponder;// Touch Event- (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;// Motion Event- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent)eventNS_AVAILABLE_IOS(3_0);- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent)eventNS_AVAILABLE_IOS(3_0);- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent)eventNS_AVAILABLE_IOS(3_0);// Remote Control Event(void)remoteControlReceivedWithEvent:(UIEvent)eventNS_AVAILABLE_IOS(4_0);从上面的代码片段,可以看到UIResponder对象可以处理TouchEvent,MotionEvent和Remote Control Event事件。还有一个非常重要的方法nextResponder,这个方法可以获取到下一个关联的Responder,Responder对象正是关联nextResponder引用组成了一个Responder链,我们称之为The Responder Chain,系统事件会沿着这个Responder Chain传播到nextResponder,直到最后一个Responder,如果依然没有处理该事件,事件就会被舍弃。但是,问题来了,系统必须先找到第一个Responder,即第一个可以响应该对象的事件。英文称之为First Responder。2) 怎样才能成为First Responder?这里还需要关注的一个概念就是First Responder,First Responder是第一个可以处理当前事件的对象,如果First Responder不能处理当前事件,则传递到nextResponder。然后依次传递给nextResponder。我们用一张官方的图,来具体地看看Responder是如何在响应链之间传递的 图-1我们来分析一下,事件的传递过程:第一步,Application对象从事件队列中获取事件对象第二步,Application对象将事件对象传递给Window,Window对象继续传递给First Responder,然后事件就会沿着Responder Chain(响应者链)传递,直到找到可以处理它的对象。基于上面的讨论,事件的传递过程,我们基本已经讨论清楚。但是,仅仅是讨论还不够,我们缺乏必要的论据,关于事件传递的证明,我会在后面给出代码证明。这里,我们先来关注一个问题:对于TouchEvents事件,系统是如何获取到当前正在点击的视图对象的呢?(其实就是寻找First Responder)这依赖于UIView里面的两个方法:- (nullableUIView)hitTest:(CGPoint)point withEvent:(nullableUIEvent)event;- (BOOL)pointInside:(CGPoint)point withEvent:(nullableUIEvent*)event;第一个方法会返回当前点击的View对象,第二个方法判断当前点击的坐标是否在当前视图边界范围内。如果在当前视图范围内,则返回YES,否则,返回NO。第一个方法会根据第二个方法的判断返回当前点击的视图。下面我们通过一个比较直观的图形来讲述iOS系统获取当前点击视图对象的过程: 图-2假设用户点击了视图D:1) 检测到点击坐标在View A范围之内。2) 继续检测点击范围是否在其子视图B,C范围内。发现点击范围在视图C范围内,则忽略掉B视图及其子视图分支。3) 继续检测点击范围是否在其子视图D范围内,如果是,则用户当前视图即为视图D。如果不是,继续检测其子视图。根据上述分析:iOS系统会从父视图向子视图依次查找,直到找到点击范围在当前视图边界范围以内。如果点击范围在某子视图范围内,并且没有了子视图,则该视图即为当前点击视图。如果点击范围在某子视图范围之内,并且不在其子视图范围之内,则点击视图即为当前点击视图。PS:感兴趣的同学可以自己去证明一下点击视图的查找过程。下面开始事件传递的证明: 图-3为此我们创建如上图所示的一个简单app,三种颜色View分别对应类红色:FirstView绿色:SecondView蓝色:ThirdView我们以Remote Control Events为例,来看看事件的传递过程:首先,我们让SecondView成为First Responder- (BOOL)canBecomeFirstResponder {returnYES;}// 然后在ViewController中,执行如下代码[_secondView becomeFirstResponder];然后,在三个视图分别添加如下测试语句:FirstView- (void)remoteControlReceivedWithEvent:(UIEvent*)event {switch(event.subtype) {caseUIEventSubtypeRemoteControlPlay:NSLog(@"FirstView:Play");break;default:break;    }}SecondView- (void)remoteControlReceivedWithEvent:(UIEvent*)event {switch(event.subtype) {caseUIEventSubtypeRemoteControlPlay:NSLog(@"SecondView:Play");break;default:break;    }}ThirdView- (void)remoteControlReceivedWithEvent:(UIEvent*)event {switch(event.subtype) {caseUIEventSubtypeRemoteControlPlay:NSLog(@"ThirdView:Play");break;default:break;    }}运行,从屏幕底部拉出音频播放界面,点击播放。这里会触发Remote Control Event,回调上图中的方法。 图-4看到如下输出日志:EventDelivery[4559:323237]SecondView:Play注释掉SecondView里面的remoteControlReceivedWithEvent:,我们可以看到如下输出日志:EventDelivery[4559:323237]ThirdView:Play这里的现象说明:Remote Control Event会沿着父视图往子视图传递,即父视图的nextResponder就是其子视图。这里大家可以考虑一下,如果当前视图有多个直接的子视图呢?nextResponder会是哪一个?请读者们自行证明。这里,我们更进一步证明,事件是否会从View传递给ViewController,注释掉三个视图里面的remoteControlReceivedWithEvent:方法,并在ViewController中重写该方法,同时添加打印日志输出,运行,可以看到如下日志输出:EventDelivery[4559:323237]ViewController:Play这更进一步证明了Responder的传递方向符合上面的分析。总结iOS系统将事件分为三类:Touch EventsMotion EventsRemote Control Events根据三类事件获取First Responder方式的不同,又可以将事件分为:Touch EventsMotion Events and Remote Control Events第一类事件通过获取当前用户交互的界面组件,即为First Responder第二类事件的First Responder由用户手动指定。成为First Responder必须实现如下两个步骤:重写canBecomeFirstResponder方法,返回YES给UIResponder对象发送becomeFirstResponder消息综上所述,事件的传递过程可以分为两步:第一步,获取到First Responder,不同的事件有不同的获取方式。第二步,从First Responder沿着Responder Chain传递到nextResponder,直到事件被处理或者舍弃。常见的Responder传递方向有:Initial View->Parent View->ViewController->Window->Application如果最终传递到Application对象,依然没有对事件作出响应,事件就会被舍弃掉。通常来说,子视图的nextResponder即为其父视图。如果子视图直接依附于ViewController,则该子视图的nextResponder即为其依附的ViewController
作文投稿

iOS事件传递一文由杰瑞文章网免费提供,本站为公益性作文网站,此作文为网上收集或网友提供,版权归原作者所有,如果侵犯了您的权益,请及时与我们联系,我们会立即删除!

杰瑞文章网友情提示:请不要直接抄作文用来交作业。你可以学习、借鉴、期待你写出更好的作文。

iOS事件传递相关的作文:

    无相关信息

说说你对这篇作文的看法吧