IOS Event Handle.docx

上传人:b****6 文档编号:8958823 上传时间:2023-02-02 格式:DOCX 页数:19 大小:460.17KB
下载 相关 举报
IOS Event Handle.docx_第1页
第1页 / 共19页
IOS Event Handle.docx_第2页
第2页 / 共19页
IOS Event Handle.docx_第3页
第3页 / 共19页
IOS Event Handle.docx_第4页
第4页 / 共19页
IOS Event Handle.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

IOS Event Handle.docx

《IOS Event Handle.docx》由会员分享,可在线阅读,更多相关《IOS Event Handle.docx(19页珍藏版)》请在冰豆网上搜索。

IOS Event Handle.docx

IOSEventHandle

IOS事件处理

概述

事件

一个事件即由硬件捕捉并产生的一个表示用户操作设备的对象并发送给IOS——例如:

一个手指点击屏幕或摇动设备。

许多event都是UIKit框架中UIEvent类的实例。

UIEvent对象可能封装了用户事件所关联的状态,像关联的点击。

UIEvent对象同时也记录了事件所产生的时刻。

当一个用户事件发生时——例如,当手指点击屏幕并在其上移动——IOS连续发送事件对象给应用程序进行处理。

UIKit当前可识别三种类型的事件:

点击事件,摇动事件及远程控制事件。

UIEvent类对其定义了enum常量:

typedefenum{

UIEventTypeTouches,

UIEventTypeMotion,

UIEventTypeRemoteControl

}UIEventType;

typedefenum{

UIEventSubtypeNone=0,

UIEventSubtypeMotionShake=1,

UIEventSubtypeRemoteControlPlay=100,

UIEventSubtypeRemoteControlPause=101,

UIEventSubtypeRemoteControlStop=102,

UIEventSubtypeRemoteControlTogglePlayPause=103,

UIEventSubtypeRemoteControlNextTrack=104,

UIEventSubtypeRemoteControlPreviousTrack=105,

UIEventSubtypeRemoteControlBeginSeekingBackward=106,

UIEventSubtypeRemoteControlEndSeekingBackward=107,

UIEventSubtypeRemoteControlBeginSeekingForward=108,

UIEventSubtypeRemoteControlEndSeekingForward=109

}UIEventSubtype;

每个事件都有其对应的事件类型和子事件类型,它们可以由UIEvent对象的type和subtype属性进行访问。

事件类型包括点击事件,摇动事件及远程控制事件。

在IOS3.0中,包括了摇动子事件类型(UIEventSubtypeMotionShake)及多种远程控制子事件类型;点击事件所对应的子事件类型为UIEventSubtypeNone。

你不应该在你代码中retain一个UIEvent对象。

如果你需要保留一个事件对象的当前状态为以后进行处理,你应该通过合适的方法(使用实例变量或字典对象)拷贝或保存状态值。

事件传递

从事件发生到其处理的对象,传递要经过相当长及特殊的一段过程。

当用户点击设备屏幕时,IOS捕捉到一系列的触摸,将其打包到UIEvent对象中并放置到应用程序活动事件队列中。

如果系统检测到摇动设置为一个有效的移动事件,则也将其打包并放置到应用程序活动事件队列中。

单例UIApplication对象管理应用程序,从事件队列中取出最前面的事件并将其分发以便处理。

通常,其发送事件给应用程序的主窗口——即聚焦于用户交互的窗口——窗口对象代表窗口再发送事件给初始对象进行处理。

初始对象对于点击事件和摇动事件是不相同的。

点击事件。

窗口对象使用hit-testing及响应者链表去找到对该事件响应的视图。

在hit-testing中,窗口找到视图继承树中最上层的视图并调用hitTest:

withEvent:

方法;该方法递归调用视图继承树中每个视图的pointInSide:

withEvent:

方法并在其返回true后,从该视图开始沿着继承树向下,直到找到一个点击事件在其范围之内的子视图。

该子视图即为hit-test视图。

如果该hit-test视图无法处理该事件,则事件沿着响应者链表进行传递直至找到能处理该事件的视图。

一个点击对象在其生命周期中一直与hit-test视图相关联,即使点击对象移动到一样该视图之外(?

)。

摇动及远程控制事件。

窗口对象发送每个摇动及远程控制事件给首响应者进行处理。

尽管hit-test视图和首响应者通常是同一个视图对象,但它们并不总是相同。

UIApplication对象及每个UIWindow对象在sendEvent:

方法中进行事件传递,因为这些方法是从应用程序传递来事件的汇集点,所以你可以继承UIApplication或UIWindow并重载sendEvent:

方法来监控事件(只有少量的应用程序需要此实现)。

如果你重载了该方法,请确保调用了超类的sendEvent:

方法。

无论如何都不要篡改事件的分发。

响应对象和响应者链

前面的讨论已涉及到响应者的概念。

那什么是响应者及它是如何适应消息分发的框架呢?

响应者对象是一个能接收并处理事件的对象。

UIResponser是所有响应者对象对的基类,另一个熟悉并简单的名字为响应者。

该基类定义了一系列编程接口,不但为事件处理进行服务而且还提供了通用的响应行为处理。

UIApplication,UIView及所有作为UIView子类的UIKit类(包括UIWindow)都直接及间接的继承自UIResponser,所有的这些类的实例都是响应者对象。

首响应者是应用程序的一个响应者对象(通常为UIView)作为接收除点击事件以外其它事件的首个响应对象。

UIWindow对象通过消息发送摇动或远程控制事件给首响应者,让其对事件进行优先处理。

为了能接收到UIWindow对象发送来的消息,响应者对象必需申明canBecomeFirstResponser方法并返回Yes;并能接收到becomeFirstResponser消息(该方法可以在对象内部进行调用)。

首响应者是Window中的第一个视图用以接收以下的事件或消息:

摇动事件——通过调用UIResponser的摇动处理方法

远程控制事件——通过调用UIResponser的remoteControlReceivedWithEvent方法

操作消息——当用户操作了Control(像按钮或滑块)便没有指定消息的接收者

Editing-MenuMessage

首响应者也在文字编辑中扮演作用。

当对TextView或TextField聚焦进行输入时即成为了首响应者,并促使了虚拟键盘的出现。

注:

应用程序必需显式的为摇动,远程控制事件及editing-menu消息处理设置首响应者,当用户点击TextView或TextField时,UIKit自动将其设置为首响应者。

如果首响应者或hit-test视图不处理收到的消息,UIkit则通过消息的形式将事件转发到响应者链的下一个响应者,看其是否能过该消息进行处理。

响应者链是一系列已连接的响应者对象,事件或消息在其路径上进行传递。

在其上允许响应者将事件处理的责任传递给高层的其它响应者。

应用程序根据响应者的处理能力将事件向上进行传递。

因为hit-test视图是一个响应者对象,当应用程序接收到点击事件时可能会对其进行更进一步的处理。

响应者链包括一系列的下一个响应者(每一个通过nextResponser方法返回)。

如下图所示。

当系统转发了一个点击事件,首先将其发送给特殊的视图。

对于点击事件,这个特殊视图为调用hitTest:

withEvent方法所返回的视图;对于它事件或消息,该特殊视图即为首响应者。

如果首个视图无法处理收到的事件,则其通过在响应者链中的特殊路径向上传递。

1.hit-test视图或首响应者发送事件或消息给其对应的视图控制器,如果该控制器存在;如果控制器不存在,则将其传递给它的父视图

2.如果视图或它的控制器无法处理收到的事件或消息,则将其传递给该视图的父视图

3.每一个在视图继承树中的上层视图如果不能处理收到的事件或消息,则重复上面的步骤1,2

4.在视图继承树的最上层视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给窗口对象进行处理

5.如果窗口对象也不能进行处理,则其将事件或消息传递给UIApplication对象

6.如果UIApplication也不能处理该事件或消息,则将其丢弃

如果你有自定义的处理摇动,远程控制事件或其它消息的视图,你不应该将事件或消息直接发送到响应者链的下一个响应者。

取代方法是调用父类的当前事件处理方法,让UIKit对消息传递进行处理。

多点触摸事件

触摸事件在IOS中是基于多点触摸模型。

取代鼠标和键盘,用户通过触摸设备的屏幕来操作对象,输入数据以及实现其它意愿。

IOS识别的一个或多个手指对屏幕进行触摸并将其作为多点触摸序列的一部分。

该序列以用户第一个手指触摸屏幕开始一直持续到最后一个手指离开屏幕。

IOS通过触摸序列来跟踪手指在屏幕上的移动并记录它们的特征,包括手指在屏幕上的位置以及触摸发生的时间。

应用程序通常会识别一组触摸为一个手势并对其进行相应的响应,例如:

放大缩小屏幕内容用于响应pinch手势,对屏幕内容进行滚动用于响应flick手势。

UIKit中许多类对于多点触摸的处理有别于其对象。

对于UIControl类的子类则特别如此,像UIButton和UISlider。

对于从UIControl继承的对象通常称为控制对象,它们期望收到特定的手势,像点击或向某方向进行拖动。

通过适应的配置,当手势发生时它们会发送操作消息给目标对象。

其它的UIkit类以不同的方式对手势进行响应,以ScrollView为例,为表视图,文本视图以及其它有大块内容区域视图提供滚动行为。

有些应用程序不需要直接响应事件,它们信赖于UIkit类所提供的行为。

如果你创建了一个UIView的子类并且希望该视图对触摸进行响应,你就必须为处理触摸事件而编写代码。

如果你希望UIKit中的对象对于事件有不同的响应,你就必须对UIkit中使用到的该类进行继承并重载合适的事件处理方法。

事件和触摸

在IOS中,触摸表示手指在屏幕上的接触或移动并作为唯一多点触摸序列的一部分。

例如:

挤(pinch-close)手势有两个触摸:

两个手指在屏幕上以相反的方向向对方移动。

同时也有一个手指操作的简单手势,例如:

单击,双击,拖动和滑动(flick)。

应用程序也有可能处理复杂的手势。

一个具有UIEventTypeTouches类型的UIEvent对象表示一个触摸事件。

当手指触摸屏幕并在其上移动时,系统持续的发送这些触摸事件对象给应用程序。

在触摸序列中,事件为所有触摸提供了快照,最重要的触摸为新收到的或在特定视图中改变的。

多触摸序列从第一个手指触摸到屏幕开始。

其它的手指可能接下来再触摸屏幕并且所有在屏幕上的手指进行移动,序列当最后一个手指离开屏幕时结束。

触摸,用UITouch对象来表示,包括触摸阶段和触摸位置。

触摸阶段,指示什么时候触摸开始,是否移动和什么时候触摸结束——即何时最后一根手指离开屏幕。

触摸位置表示与触摸相关联的对象即触摸点在对象的内部。

当手指触摸到屏幕,触摸就与窗口和视图相关联,关联关系一直维持到事件结束。

如果多点触摸同时到达,当它们所关联的视图相同时则进行统一处理。

否则,如果两个触摸在同一个视图上以很快的速度先后到达,则被认为是多次点击。

触摸对象保存触摸的位置及上次触摸位置(如果存在)在它所对应的窗口或视图中。

一个事件对象包括了在本次触摸序列中所有的触摸对象并能提供触摸对象所操作的窗口或视图(如图2-2)。

所改变的触摸属性为触摸阶段,在视图中的位置,上一次的位置以及触摸时间戳。

事件处理代码计算这些属性以决定如何对其进行响应。

因为系统可以在任何时候取消多点触摸序列,所以应用应能对其进行相应的处理。

取消会发生在有系统消息到达的时候,例如一个来电或短消息。

事件处理方法

大多数应用程序可以在自定义视图上检测并处理其感兴趣的手势。

这些手势包括点击(单击或多击),pinch(放大或缩小视图),滑动,拖动一个视图或用两个手指来旋转一个视图。

你可以定义触摸事件处理代码来识别并处理这些手势,但这样的代码将十分的复杂,可能会有很多bug且会耗费大量时间。

替代方法是在IOS3.2以后,你可以使用手势识别器类来定义和处理这些通用的手势。

要使用手势识别器类,首先进行初始化,将其与要接收触摸的视图联系,对其进行配置,并分配该手势的处理对象及处理方法。

当一个手势识别器识别到一个手势时,它将发送处理方法给处理对象来对手势进行响应。

你可以通过继承UIGestureRecognizer类来定义自己的手势识别器类。

自定义的手势识别器需要你对一个多触摸序列中的触摸流进行分析来识别特定的手势。

控制触摸事件投递

UIKit提供给应用程序事件处理编程接口或可以完全关闭UIEvent对象流,下面的则描述了操作方法。

关闭事件投递。

缺省情况下,视图接收触摸事件,但你可以设置视图的userInteractionEnable属性为NO来关闭对触摸事件的投递,一个视图在隐藏或透明状态下也无法接收到触摸事件。

在一段时间内关闭事件投递。

应用程序可以调用UIApplication的beginIgnoringInteraction

Events方法并在以后的某个时间调用endIgnoringInteractionEvents方法。

第一方法使application对象完成停止对触摸事件的接收,第二个方法则是恢复application对象对触摸事件的接收。

你可能在应用中运行动画时关闭对事件的投递。

打开多触摸事件投递。

缺省情况下,视图只会对触摸序列中的第一个触摸进行响应并忽略其它触摸。

如果你需要处理多触摸则必需打开该视图的多触摸处理能力。

你可以通过编程设置multipleTouchEnable属性为YES或者通过InterfaceBuilder中设置勾选相关属性。

限制触摸事件给特定视图。

缺省情况下,视图的exclusiveTouch属性设置为NO,表示该视图并不限制当前窗口中的其它视图接收触摸事件。

如果你设置其值为YES,则标识了该视图并只有该视图能对消息进行跟踪处理。

窗口中的其它视图则无法收到触摸事件。

限制触摸事件给子视图。

一个从UIView继承的自定义视图,可以重载hitTest:

withEvent方法来限制将多触摸事件传递给其子视图。

处理多触摸事件

要处理多触摸事件,你首先必须创建一个响应者的子类。

该类可以从以下的任一个进行继承:

一个自定义视图(UIView的子类)

一个UIViewController类的子类或从UIKit中其子控制器类继承

一个UIkit中View或控制类的子类,像UIImageView或UISlider

一个UIApplication或UIWindow的子类(不常用)

一个视图控制器一般通过响应者链来接收事件,触摸事件一开始便发送给它对应的视图如果该视图没有重载事件处理方法。

如果要自定义的子类实例能接收触摸事件,你必须为触摸事件的处理申明一个或多个UIResponser方法,方法描述见下。

除此之外,对应的视图应可见(不是透明或隐藏)并且userInteractionEnabled应为YES(缺省值)。

接下来的章节描述事件处理方法,描述处理通用手势的方法,展示了一个用于处理复杂多触摸事件的响应者例子,讨论事件转发和事件处理所建议使用的技术。

事件处理方法

在一个多触摸序列中,应用程序分发一系列的事件消息给目的响应者。

为了能接收并响应这些消息,响应者类必须至少申明一个由UIResponser类定义的如下方法,在一些情况下,则必须申明全部的方法。

-(void)touchesBegan:

(NSSet*)toucheswithEvent:

(UIEvent*)event;

-(void)touchesMoved:

(NSSet*)toucheswithEvent:

(UIEvent*)event;

-(void)touchesEnded:

(NSSet*)toucheswithEvent:

(UIEvent*)event;

-(void)touchesCancelled:

(NSSet*)toucheswithEvent:

(UIEvent*)event

应用程序在一个给定的触摸阶段当有新的触摸或改变的触摸时发送这些消息:

∙当一根或多根手指触摸到屏幕时发送touchesBegan:

withEvent:

消息。

∙当一根或多根手指在屏幕上移动时发送touchesMoved:

withEvent:

消息。

∙当一根或多根手指离开屏幕时发送touchesEnded:

withEvent:

消息。

∙当触摸序列被一个系统事件(来电)打断时发送touchesCancelled:

withEvent:

消息。

上述的每一个消息都与一个触摸阶段相关联,例如:

touchesBegan:

withEvent:

消息与UITouchPhaseBegin相关联。

你可以通过访问任何UITouch对象的phase属性获得该触摸所处的阶段。

每个调用事件处理方法的消息都包括两个参数。

第一个参数是一组表示在给定触摸阶段新收到或改变了的UITouch对象。

第二个参数则是表示触摸事件的UIEvent对象。

从事件对象中你可能获得该事件的所有触摸对象或者是根据给定视图或窗口过滤了的触摸对象。

其中的一些触摸对象表示该触摸自从上个事件来没有发生改变或该触摸在不同的触摸阶段发生了改变。

基本触摸事件处理

你通常会处理一个给定阶段的事件通过从传入的一系列UITouch中获得一个或多个UITouch对象,计算属性,获得位置并进行相应的处理。

这些对象表示申明的处理方法中在一个给定阶段新收到或改变了的触摸。

如果收到了任一个触摸对象,你可以向NSSet对象发送anyObject消息,该消息导致对应视图只接收触摸序列中的第一个触摸(multipleTouchesEnabled属性设置为NO)。

UITouch对象的一个重要方法为locationInView:

,如果为该方法传递self参数,则表示该触摸的位置位于接收视图中的坐标。

一个并行的方法告诉你该触摸上一次的位置(previousLocationInView:

)。

UITouch对象的tapCount属性告诉你本次触摸点击了多少次,timestamp属性告诉你本次触摸何时创建以及最后一次改变的时间,phase属性则告诉你本次触摸所处的阶段。

由于某些原因,你可能对本次触摸序列中那些自从上个阶段以来没有改变或处在不同阶段的同一触摸感兴趣,你可以从传入的UIEvent对象中获得它们。

下图中展示了一个UIEvent对象中包括四个触摸对象。

要获得所有的触摸对象,你可以调用事件对象的allTouches方法。

如果你只对在给定窗口中发生的触摸感兴趣,你将给UIEvent对象发送touchesForWindow:

消息,如下图所示。

如果你只对在给定视图中发生的触摸感兴趣,你将给UIEvent对象发送touchesForView:

消息,如下图所示。

如果一个响应者在对事件序列中的事件进行处理时创建了持久化对象,则应该申明touchCancelled:

withEvent:

方法,并在该方法中对持久化对象进行释放。

事件取消通常发生在外部事件——例如来电——打断了当前应用程序的事件处理。

需要注意的是响应者对象也应该释放在touchEnded:

withEvent:

方法中进行释放的对象。

重要:

如果自定义的响应者是UIView或UIViewController的子类,则你必须申明全部四个UIResponser对象的事件处理方法。

如果自定义响应者为UIKit中的响应者类,则你不需要对全部四个事件处理方法进行申明。

在那些重载的事件处理方法中,一定要调用其超类的事件处理方法([supertouchBegan:

toucheswithEvent:

theEvent])。

这样做的原因很简单:

所有的视图都处理触摸,包括你自定义的,都希望收到完整的触摸事件流。

如果你阻止一个UIKit响应者对象接收在给定阶段中的触摸事件,则接下来的行为将是未定义并不可预计。

点击手势处理

点击是在IOS应用中最常用的手势:

用户通过手指点击屏幕上的对象。

响应者对象可以对单击,双击以及三击进行不同的响应。

要确定用户点击的次数,你可以调用UITouch对象的tapCount属性获得。

获得点击次数的最佳位置是在touchBegan:

withEvent:

和touchEnded:

withEvent:

方法中。

而第二个方法则更为合适,因为它在用户手指从点击到离开屏幕的阶段中进行响应。

通过在touch-up阶段计算点击次数,你可以确认手指是否真正的完成点击,或者只是手指按到屏幕上并进行移动。

下面的代码展示了如何在指定视图中对双击进行判断。

(void)touchesCancelled:

(NSSet*)toucheswithEvent:

(UIEvent*)event{}

(void)touchesBegan:

(NSSet*)toucheswithEvent:

(UIEvent*)event{}

(void)touchesMoved:

(NSSet*)toucheswithEvent:

(UIEvent*)event{}

(void)touchesEnded:

(NSSet*)toucheswithEvent:

(UIEvent*)event{

for(UITouch*touchintouches){

if(touch.tapCount>=2){

[self.superviewbringSubviewToFront:

self];

}

}

}

如果响应者对象将对单击和双击操作进行不同的处理则会变得有点复杂。

例如:

单击操作为了选中对象而双击操作为了显示一个视图并对其进行编辑。

应用程序应该如何判断单击并非是双击的第一部分呢?

下面的代码示例了对消息处理方法的声明让进行双击操作时增加所点击视图的大小而单击操作时减少所点击视图的大小。

-(void)touchesBegan:

(NSSet*)toucheswithEvent:

(UIEvent*)event{

UITouch*touch=[touchesanyObject];

if(2==touch.tapCount){

[NSObjectcancelPreviousPerformRequestsWithTarget:

self];

}

}

-(void)touchesMoved:

(NSSet*)toucheswithEvent:

(UIEvent*)event{}

-(void)touchesEnded:

(NSSet*)toucheswithEvent:

(UIEvent*)event{

UITouch*touch=[touchesanyObject];

if(1==touch.tapCount){

NSDictionary*touchLoc=[NSDictionarydictionaryWithObject:

[NSValuevalueWithCGPoint:

[touchlocationInView:

self]]

forKey:

@"location"];

[selfperfo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 外语学习 > 英语学习

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1