




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、IOS事件处理 概述 事件 一个事件即由硬件捕捉并产生的一个表示用户操作设备的对象并发送给IOS例如: 一个手指点击屏幕或摇动设备。许多 eve nt都是UlKit框架中UlEve nt类的实例。UlEve nt 对象可能封装了用户事件所关联的状态,像关联的点击。UlEvent对象同时也记录了事件 所产生的时刻。当一个用户事件发生时一一例如,当手指点击屏幕并在其上移动一一IOS连 续发送事件对象给应用程序进行处理。 UlKit当前可识别三种类型的事件:点击事件,摇动事件及远程控制事件。UlEvent类对 其定义了 enum 常量: typedef enum UlEve ntTypeTouche
2、s, UlEve ntTypeMotio n, UlEve ntTypeRemoteC on trol UlEve ntType; typedef enum UlEve ntSubtypeN one = 0, UlEve ntSubtypeMotio nShake = 1, UlEve ntSubtypeRemoteC on trolPlay = 100, UlEve ntSubtypeRemoteC on trolPause = 101, UlEve ntSubtypeRemoteC on trolStop = 102, UlEve ntSubtypeRemoteC。ntrolToggleP
3、layPause = 103, UlEve ntSubtypeRemoteCo ntrolNextTrack = 104, UlEve ntSubtypeRemoteCo ntrolPreviousTrack = 105, UlEve ntSubtypeRemoteCo ntrolBegi nSeeki ngBackward = 106, UlEve ntSubtypeRemoteC on trolE ndSeeki ngBackward = 107, UlEve ntSubtypeRemoteCo ntrolBegi nSeeki ngForward = 108, UlEve ntSubty
4、peRemoteC on trolE ndSeeki ngForward = 109 UlEve ntSubtype; 每个事件都有其对应的事件类型和子事件类型,它们可以由UlEvent对象的type和 subtype属性进行访问。事件类型包括点击事件,摇动事件及远程控制事件。在IOS3.0 中,包括了摇动子事件类型(UlEve ntSubtypeMotio nShake )及多种远程控制子事件类 型;点击事件所对应的子事件类型为 UlEve ntSubtypeNo ne 。 你不应该在你代码中retain 一个UlEvent对象。如果你需要保留一个事件对象的当前状 态为以后进行处理,你应该通
5、过合适的方法(使用实例变量或字典对象)拷贝或保存状态 值。 事件传递 从事件发生到其处理的对象,传递要经过相当长及特殊的一段过程。当用户点击设备屏 幕时,IOS捕捉到一系列的触摸,将其打包到UlEvent对象中并放置到应用程序活动事件队 列中。如果系统检测到摇动设置为一个有效的移动事件,则也将其打包并放置到应用程序活 动事件队列中。单例UlApplicati on 对象管理应用程序,从事件队列中取出最前面的事件并 将其分发以便处理。通常,其发送事件给应用程序的主窗口一一即聚焦于用户交互的窗口一 窗口对象代表窗口再发送事件给初始对象进行处理。初始对象对于点击事件和摇动事件是 不相同的。 点击事件
6、。窗口对象使用hit-testing及响应者链表去找到对该事件响应的视图。在hittest ing中,窗口找到视图继承树中最上层的视图并调用hitTest:withEvent:方法;该方法递 归调用视图继承树中每个视图的pointInSide:withEvent:方法并在其返回true后,从该视 图开始沿着继承树向下,直到找到一个点击事件在其范围之内的子视图。该子视图即为hit test 视图。 如果该hit-test视图无法处理该事件,则事件沿着响应者链表进行传递直至找到能处理 该事件的视图。一个点击对象在其生命周期中一直与hit-test视图相关联,即使点击对象移 动到一样该视图之外(?)
7、。 摇动及远程控制事件。窗口对象发送每个摇动及远程控制事件给首响应者进行处理。 尽管hit-test视图和首响应者通常是同一个视图对象,但它们并不总是相同。 UIApplication 对象及每个UIWindow 对象在sendEvent:方法中进行事件传递,因为 这些方法是从应用程序传递来事件的汇集点,所以你可以继承UIApplication或UIWindow 并重载sendEvent:方法来监控事件(只有少量的应用程序需要此实现)。如果你重载了该 方法,请确保调用了超类的sendEvent:方法。无论如何都不要篡改事件的分发。 响应对象和响应者链 前面的讨论已涉及到响应者的概念。那什么是响
8、应者及它是如何适应消息分发的框架 呢? 响应者对象是一个能接收并处理事件的对象。UIResponser是所有响应者对象对的基 类,另一个熟悉并简单的名字为响应者。该基类定义了一系列编程接口,不但为事件处理进 行服务而且还提供了通用的响应行为处理。UIApplication ,UIView及所有作为UIView 子类的UIKit类(包括UIWindow )都直接及间接的继承自 UIResponser,所有的这些类的 实例都是响应者对象。 首响应者是应用程序的一个响应者对象(通常为 UIView )作为接收除点击事件以外其 它事件的首个响应对象。UIWindow对象通过消息发送摇动或远程控制事件给
9、首响应者,让 其对事件进行优先处理。为了能接收到 UIWindow对象发送来的消息,响应者对象必需申 明 canBecomeFirstResponser方法并返回 Yes;并能接收至U becomeFirstResponser消 息(该方法可以在对象内部进行调用)。首响应者是Win dow中的第一个视图用以接收以 下的事件或消息: 摇动事件通过调用UIResponser的摇动处理方法 远程控制事件通过调用 UIResponser 的 remoteControlReceivedWithEvent方法 操作消息一一当用户操作了 Co ntrol (像按钮或滑块)便没有指定消息的接收者 Edit i
10、n g-Me nu Message 首响应者也在文字编辑中扮演作用。当对Text View或Text Field聚焦进行输入时即成 为了首响应者,并促使了虚拟键盘的出现。 注:应用程序必需显式的为摇动,远程控制事件及edit in g-me nu 消息处理设置首响应 者,当用户点击Text View或Text Field时,UIKit自动将其设置为首响应者。 如果首响应者或hit-test视图不处理收到的消息,UIkit则通过消息的形式将事件转发到 响应者链的下一个响应者,看其是否能过该消息进行处理。 响应者链是一系列已连接的响应者对象,事件或消息在其路径上进行传递。在其上允许 响应者将事件处
11、理的责任传递给高层的其它响应者。应用程序根据响应者的处理能力将事件 向上进行传递。因为hit-test视图是一个响应者对象,当应用程序接收到点击事件时可能会 对其进行更进一步的处理。响应者链包括一系列的下一个响应者(每一个通过 nextRespo nser方法返回)。如下图所示。 Window UI Application window View superview View superview View controller View 当系统转发了一个点击事件,首先将其发送给特殊的视图。对于点击事件,这个特殊视 图为调用hitTest:withEvent方法所返回的视图;对于它事件或消息,该
12、特殊视图即为首响 应者。如果首个视图无法处理收到的事件,则其通过在响应者链中的特殊路径向上传递。 1. hit-test视图或首响应者发送事件或消息给其对应的视图控制器,如果该控制器存 在;如果控制器不存在,则将其传递给它的父视图 2. 如果视图或它的控制器无法处理收到的事件或消息,则将其传递给该视图的父视 3. 每一个在视图继承树中的上层视图如果不能处理收到的事件或消息,则重复上面 的步骤1,2 4. 在视图继承树的最上层视图,如果也不能处理收到的事件或消息,则其将事件或 消息传递给窗口对象进行处理 5. 如果窗口对象也不能进行处理,则其将事件或消息传递给UlApplication 对象 6
13、. 如果UlApplication也不能处理该事件或消息,则将其丢弃 如果你有自定义的处理摇动,远程控制事件或其它消息的视图,你不应该将事件或消息 直接发送到响应者链的下一个响应者。取代方法是调用父类的当前事件处理方法,让UlKit 对消息传递进行处理。 多点触摸事件 触摸事件在IOS中是基于多点触摸模型。取代鼠标和键盘,用户通过触摸设备的屏幕来 操作对象,输入数据以及实现其它意愿。IOS识别的一个或多个手指对屏幕进行触摸并将其 作为多点触摸序列的一部分。该序列以用户第一个手指触摸屏幕开始一直持续到最后一个手 指离开屏幕。IOS通过触摸序列来跟踪手指在屏幕上的移动并记录它们的特征,包括手指在
14、屏幕上的位置以及触摸发生的时间。应用程序通常会识别一组触摸为一个手势并对其进行相 应的响应,例如:放大缩小屏幕内容用于响应pinch手势,对屏幕内容进行滚动用于响应 flick手势。 UlKit中许多类对于多点触摸的处理有别于其对象。对于UIControl类的子类则特别如 此,像UIButton和UISlider。对于从UIControl继承的对象通常称为控制对象,它们期望收 到特定的手势,像点击或向某方向进行拖动。通过适应的配置,当手势发生时它们会发送操 作消息给目标对象。其它的 UIkit类以不同的方式对手势进行响应,以ScrollView为例,为 表视图,文本视图以及其它有大块内容区域视
15、图提供滚动行为。 有些应用程序不需要直接响应事件,它们信赖于UIkit类所提供的行为。如果你创建了 一个UIView的子类并且希望该视图对触摸进行响应,你就必须为处理触摸事件而编写代 码。如果你希望UIKit中的对象对于事件有不同的响应,你就必须对UIkit中使用到的该类进 行继承并重载合适的事件处理方法。 事件和触摸 在IOS中,触摸表示手指在屏幕上的接触或移动并作为唯一多点触摸序列的一部分。例 如:挤(pin ch-close )手势有两个触摸:两个手指在屏幕上以相反的方向向对方移动。同 时也有一个手指操作的简单手势,例如:单击,双击,拖动和滑动( flick )。应用程序也有 可能处理复
16、杂的手势。 一个具有UIEventTypeTouches 类型的UIEvent对象表示一个触摸事件。当手指触摸 屏幕并在其上移动时,系统持续的发送这些触摸事件对象给应用程序。在触摸序列中,事件 为所有触摸提供了快照,最重要的触摸为新收到的或在特定视图中改变的。多触摸序列从第 一个手指触摸到屏幕开始。其它的手指可能接下来再触摸屏幕并且所有在屏幕上的手指进行 移动,序列当最后一个手指离开屏幕时结束。 Touch 1 down Touch 2 down Touch i grid 2 moved UITouchPhaseBegan UITouchPhaseBecin UHouchPhaseMoved
17、触摸,用UlTouch对象来表示,包括触摸阶段和触摸位置。触摸阶段,指示什么时候触 摸开始,是否移动和什么时候触摸结束即何时最后一根手指离开屏幕。 触摸位置表示与触摸相关联的对象即触摸点在对象的内部。当手指触摸到屏幕,触摸就 与窗口和视图相关联,关联关系一直维持到事件结束。如果多点触摸同时到达,当它们所关 联的视图相同时则进行统一处理。否则,如果两个触摸在同一个视图上以很快的速度先后到 达,则被认为是多次点击。触摸对象保存触摸的位置及上次触摸位置(如果存在)在它所对 应的窗口或视图中。 一个事件对象包括了在本次触摸序列中所有的触摸对象并能提供触摸对象所操作的窗口 或视图(如图2-2)。所改变的
18、触摸属性为触摸阶段,在视图中的位置,上一次的位置以及 触摸时间戳。事件处理代码计算这些属性以决定如何对其进行响应。 Figure 2-2 Relationship of a UI Event object and its UlTouch objects UiTouch pase = U ITou chP haseBegan location In View = (35,501 view = ViewA UlEvent UlTouch phase = UlTouch PhaseMoved catinnlrVicw = (35,20) view = ViewA UlTouch phase = Ul
19、TouchPhaseEnded locaricnlnView = (12Q,07) view = ViewB 因为系统可以在任何时候取消多点触摸序列,所以应用应能对其进行相应的处理。取消 会发生在有系统消息到达的时候,例如一个来电或短消息。 事件处理方法 大多数应用程序可以在自定义视图上检测并处理其感兴趣的手势。这些手势包括点击 (单击或多击),pinch (放大或缩小视图),滑动,拖动一个视图或用两个手指来旋转一 个视图。 你可以定义触摸事件处理代码来识别并处理这些手势,但这样的代码将十分的复杂,可 能会有很多bug且会耗费大量时间。替代方法是在IOS3.2以后,你可以使用手势识别器类 来定
20、义和处理这些通用的手势。要使用手势识别器类,首先进行初始化,将其与要接收触摸 的视图联系,对其进行配置,并分配该手势的处理对象及处理方法。当一个手势识别器识别 到一个手势时,它将发送处理方法给处理对象来对手势进行响应。 你可以通过继承UIGestureRecognizer 类来定义自己的手势识别器类。自定义的手势 识别器需要你对一个多触摸序列中的触摸流进行分析来识别特定的手势。 控制触摸事件投递 UIKit提供给应用程序事件处理编程接口或可以完全关闭UIEvent对象流,下面的则描述 了操作方法。 关闭事件投递。缺省情况下,视图接收触摸事件,但你可以设置视图的 userInteractionE
21、nable属性为NO来关闭对触摸事件的投递,一个视图在隐藏或透明状态 下也无法接收到触摸事件。 在一段时间内关闭事件投递。应用程序可以调用UIApplicati on 的 beg inlgnoringln teracti on Events方法并在以后的某个时间调用 endIgnoringlnteractionEvents方法。第一方法使 applicatio n对象完成停止对触摸事件的接收,第二个方法则是恢复applicati on对象对触 摸事件的接收。你可能在应用中运行动画时关闭对事件的投递。 打开多触摸事件投递。缺省情况下,视图只会对触摸序列中的第一个触摸进行响应并忽 略其它触摸。如果
22、你需要处理多触摸则必需打开该视图的多触摸处理能力。你可以通过编程 设置multipleTouchE nable 属性为YES或者通过In terface Builder中设置勾选相关属性。 限制触摸事件给特定视图。 缺省情况下,视图的exclusiveTouch属性设置为NO,表 示该视图并不限制当前窗口中的其它视图接收触摸事件。如果你设置其值为YES则标识了 该视图并只有该视图能对消息进行跟踪处理。窗口中的其它视图则无法收到触摸事件。 限制触摸事件给子视图。一个从UIView继承的自定义视图,可以重载 hitTest:withEve nt方法来限制将多触摸事件传递给其子视图。 处理多触摸事件
23、 要处理多触摸事件,你首先必须创建一个响应者的子类。该类可以从以下的任一个进行 一个自定义视图(UlView的子类) 一个UlViewController类的子类或从UlKit中其子控制器类继承 一个Ulkit中View 或控制类的子类,像 UllmageView 或UlSlider 一个UlApplication或UlWindow 的子类(不常用) 一个视图控制器一般通过响应者链来接收事件,触摸事件一开始便发送给它对应的视图 如果该视图没有重载事件处理方法。 如果要自定义的子类实例能接收触摸事件,你必须为触摸事件的处理申明一个或多个 UlResponser方法,方法描述见下。除此之外,对应的
24、视图应可见(不是透明或隐藏)并且 userlnteractionEnabled应为 YES (缺省值)。 接下来的章节描述事件处理方法,描述处理通用手势的方法,展示了一个用于处理复杂 多触摸事件的响应者例子,讨论事件转发和事件处理所建议使用的技术。 事件处理方法 在一个多触摸序列中,应用程序分发一系列的事件消息给目的响应者。为了能接收并响 应这些消息,响应者类必须至少申明一个由UlResponser类定义的如下方法,在一些情况 下,贝U必须申明全部的方法。 (void)touchesBega n:(NSSet *)touches withEve nt:(UIEve nt *)eve nt; (
25、void)touchesMoved:(NSSet *)touches withEve nt:(UIEve nt *)eve nt; (void)touchesE nded:(NSSet *)touches withEve nt:(UIEve nt *)eve nt; (void)touchesCa ncelled:(NSSet *)touches withEve nt:(UIEve nt *)eve nt 应用程序在一个给定的触摸阶段当有新的触摸或改变的触摸时发送这些消息: 当一根或多根手指触摸到屏幕时发送touchesBega n:withEve nt:消息。 当一根或多根手指在屏幕上移动时
26、发送touchesMoved:withEve nt:消息。 当一根或多根手指离开屏幕时发送 touchesE nded:withEve nt:消息。 当触摸序列被一个系统事件(来电)打断时发送touchesCa ncelled:withEve nt:消 息。 上述的每一个消息都与一个触摸阶段相关联,例如:touchesBega n:withEve nt:消息与 UlTouchPhaseBegin 相关联。你可以通过访问任何 UlTouch对象的phase属性获得该触 摸所处的阶段。 每个调用事件处理方法的消息都包括两个参数。第一个参数是一组表示在给定触摸阶段 新收到或改变了的UlTouch对象
27、。第二个参数则是表示触摸事件的UlEvent对象。从事件 对象中你可能获得该事件的所有触摸对象或者是根据给定视图或窗口过滤了的触摸对象。其 中的一些触摸对象表示该触摸自从上个事件来没有发生改变或该触摸在不同的触摸阶段发生 了改变。 基本触摸事件处理 你通常会处理一个给定阶段的事件通过从传入的一系列UlTouch中获得一个或多个 UlTouch对象,计算属性,获得位置并进行相应的处理。这些对象表示申明的处理方法中在 一个给定阶段新收到或改变了的触摸。如果收到了任一个触摸对象,你可以向NSSet对象 发送anyObject消息,该消息导致对应视图只接收触摸序列中的第一个触摸 (multipleTo
28、uchesEnabled 属性设置为 NO )。 UlTouch对象的一个重要方法为locationlnView:,如果为该方法传递self参数,则表 示该触摸的位置位于接收视图中的坐标。一个并行的方法告诉你该触摸上一次的位置 (previousLocationlnView: )。UlTouch对象的tapCount 属性告诉你本次触摸点击了多 少次,timestamp属性告诉你本次触摸何时创建以及最后一次改变的时间,phase属性则 告诉你本次触摸所处的阶段。 由于某些原因,你可能对本次触摸序列中那些自从上个阶段以来没有改变或处在不同阶 段的同一触摸感兴趣,你可以从传入的UlEvent对象中
29、获得它们。下图中展示了一个 UlEvent对象中包括四个触摸对象。要获得所有的触摸对象,你可以调用事件对象的 allTouches 方法。 Ul Event UlTouch UlTouch UlTouch 如果你只对在给定窗口中发生的触摸感兴趣,你将给UlEvent对象发送 touchesForWi ndow: 消息,如下图所示。 Ullouch Ullouch Ullouch UlTouch 如果你只对在给定视图中发生的触摸感兴趣,你将给UlEvent对象发送 touchesForView:消息,如下图所示。 Window B View C 如果一个响应者在对事件序列中的事件进行处理时创建了
30、持久化对象,则应该申明 touchCa ncelled:withEve nt: 方法,并在该方法中对持久化对象进行释放。事件取消通常 发生在外部事件一一例如来电一一打断了当前应用程序的事件处理。需要注意的是响应者对 象也应该释放在touchEnded:withEvent:方法中进行释放的对象。 重要:如果自定义的响应者是 UlView或UlViewController的子类,则你必须申明全部 四个UlResponser对象的事件处理方法。如果自定义响应者为UlKit中的响应者类,则你不 需要对全部四个事件处理方法进行申明。在那些重载的事件处理方法中,一定要调用其超类 的事件处理方法(super
31、 touchBegan:touches withEvent:theEvent)。这样做的原因 很简单:所有的视图都处理触摸,包括你自定义的,都希望收到完整的触摸事件流。如果你 阻止一个UlKit响应者对象接收在给定阶段中的触摸事件,则接下来的行为将是未定义并不 可预计。 点击是在IOS应用中最常用的手势:用户通过手指点击屏幕上的对象。响应者对象可以 对单击,双击以及三击进行不同的响应。要确定用户点击的次数,你可以调用UlTouch对 象的tapCount 属性获得。 获得点击次数的最佳位置是在 touchBegan:withEvent:和touchEnded:withEvent:方 法中。而第
32、二个方法则更为合适,因为它在用户手指从点击到离开屏幕的阶段中进行响应。 通过在touch-up阶段计算点击次数,你可以确认手指是否真正的完成点击,或者只是手指 按到屏幕上并进行移动。 下面的代码展示了如何在指定视图中对双击进行判断。 (void)touchesCa ncelled:(NSSet *)touches withEve nt:(UIEve nt *)eve nt (void)touchesBega n:(NSSet *)touches withEve nt:(UIEve nt *)eve nt (void)touchesMoved:(NSSet *)touches withEve n
33、t:(UIEve nt *)eve nt (void)touchesE nded:(NSSet *)touches withEve nt:(UIEve nt *)eve nt for (UITouch *touch in touches) if (touch.t apCou nt = 2) self.superview brin gSubviewToFr on t:self; 如果响应者对象将对单击和双击操作进行不同的处理则会变得有点复杂。例如:单击操 作为了选中对象而双击操作为了显示一个视图并对其进行编辑。应用程序应该如何判断单击 并非是双击的第一部分呢?下面的代码示例了对消息处理方法的声明
34、让进行双击操作时增加 所点击视图的大小而单击操作时减少所点击视图的大小。 -(void )touchesBegan:(NSSet *)touches withEvent:( UIEvent *)event UITouch *touch = touches anyObject ; if (2 = touch. tapCount ) NSObject cancelPreviousPerformRequestsWithTarget:self; -(void )touchesMoved:( NSSet *)touches withEvent:( UIEvent *)event -(void )touc
35、hesEnded:( NSSet *)touches withEvent:( UIEvent *)event UITouch *touch = touches anyObject ; if (1 = touch. tapCount ) NSDictionary *touchLoc = NSDictionary dictionaryWithObject NSValue valueWithCGPoint:touch forKey :location; self performSelector :selector (handleSingleTap:) withObject :touchLoc aft
36、erDelay :0.3; else if (2 = touch. tapCount ) /double-tap: in crease view size by 10% CGRect viewFrame = self.frame ; viewFrame. size.width += self.frame .size.width * 0.1; viewFrame. size.height += self.frame .size.height * 0.1; viewFrame. origin .x -= (self.frame .origin .x * 0.1)/ 2.0; viewFrame.
37、origin .y -= (self.frame .origin .y * 0.1)/2.0; UlView beg inAn imatio ns:nil con text :NULL; self setFrame :viewFrame; UlView commitAnimations; -(void )touchesCancelled:( NSSet *)touches withEvent:( UIEvent *)event -(void )handleSingleTap:( NSDictionary *)touches /Sin gle-tap: decrease view size by
38、 10% CGRect viewFrame = self.frame ; viewFrame. size.width -= self.frame .size.width * 0.1; viewFrame. size.height -= self.frame .size.height * 0.1; viewFrame. origin .x += (self.frame .origin .x * 0.1)/2.0; viewFrame. origin .y += (self.frame .origin .y * 0.1)/2.0; UlView beg inAn imatio ns:nil con
39、 text :NULL; self setFrame :viewFrame; UlView commitAnimations ; 以下是对上面代码的说明: 在touchEnded:withEvent:方法中,当点击的次数为1时,响应者对象向其自身发送 performSelector:withObject:afterDelay:消息。选择子标识了对单击事件响应的方法;第 二个参数是一个 NSValue或NSDictionary 对象,用来保存UITouch对象的一些状态;延 迟时间是表示单击和双击之间有意义的时间间隔。 注:因为touch对象在触摸序列的处理中是可变的,所以你不能retain 一
40、个touch对 象并假设它的状态不会发生改变(你也不能拷贝一个touch对象,因为其没有申明 NSCopying协议)。但如果你需要保存touch对象的某些状态,你需要将touch对象的 状态用NSVaule对象,字典对象或其它类似对象进行保存。 在touchBegan:withEvent:方法中,当点击的次数为 2时,响应者对象通过调用 NSObject类的cancelPerformRequestsWithTarget:方法取消被挂起的延迟调用。如果点 击次数不为2,则在延迟时间到达后,将会调用选择子所指定的单击事件处理方法。 在touchEnded:withEvent:方法中,当点击的次数
41、为 2时,响应者对双击的操作进行 处理。 处理滑动或拖动手势 水平或垂直方面的滑动属于简单的手势,你可以在你的代码中进行跟踪并对其进行处 理。要检测一个滑动手势,你必须跟踪与所希望的移动轴相反的用户手指的移动,但是滑动 的组成最终还是由你来决定。换句话说,你需要确定用户手指是否移动的足够远,是否以直 线方式向前移动,是否移动的足够快。要对上述的内容进行判断,你要存储下初始时的触摸 位置,然后与touch-moved事件中位置进行比较。 下面的代码示例了一些基本的跟踪方法用于判断视图上进行水平方向的滑动。在这个例 子中首先将触摸的初始位置存储到startTouchPosition实例变量中。当用
42、户移动手指,代码 对当前的触摸位置与初始触摸位置进行比较来确定是否为滑动操作。如果手指在垂直方向上 移动了太多的距离,则不认为是一次滑动而进行不同的处理。一旦滑动足够远并被认为是一 个完整的手势时会调用相应的操作。要在垂直方向上判断滑动操作,你也可以使用类似的代 码,只不过对对X和丫方向进行交换。 #defi ne HORIZ_SWIPE_DRAG_MIN12 #defi ne VERT_SWIPE_DRAG_MIN4 #pragma mark eve nt han dle -(void )touchesBegan:( NSSet *)touches withEvent:(UIEvent *)
43、event UITouch *touch = touches anyObject ; startTouchPositi on = touch locati onlnView :self; -(void )touchesMoved:( NSSet *)touches withEvent:(UIEvent *)event UITouch *touch = touches anyObject ; CGPoint currentTouchPosition = touch locationlnView :self; if (fabs (startTouchPosition .x - currentTou
44、chPosition. x) = HORIZ_SWIPE_DRAG_MIN) if (NULL = poi nt) point = ( CGPoint *)malloc (sizeof(CGPoint ); CFDictionarySetValue(touchBeginPoints, touch, point); *point = touchlocationlnView:self.superview ; 下面的代码示例了如何从字典对象中取得初始位置数据并获得对应触摸的当前位置 -(void )comparePointForTouches: ( NSSet *)touches NSArray *
45、sortedTouch = touches allObjects sortedArrayUsingSelector:selector (compareAddress:); UITouch *touch1 = sortedTouch objectAtIndex :0; UITouch *touch2 = sortedTouch objectAtIndex :1; CGPoint beginPoint1 = *(CGPoint*)CFDictionaryGetValue(touchBeginPoints, touchl); CGPoint currentPoint1 = touch1 locati
46、onlnView :self.superview ; CGPoint beginPoint2 = *(CGPoint*)CFDictionaryGetValue(touchBeginPoints, touch2); CGPoint currentPoint2 = touch2 locationlnView :self.superview ; /Compare curre nt and begi n point 更具体的操作可参考apple提供的MoveMe示例 Hit-Test ing 你自己定义的响应者可以使用hit-testing来找到要对与触摸对应的该响应者中的子视图 或子层(subLa
47、yer )并对其进行合适的处理。要完成该操作可以调用视图的 hitTest:withEvent:方法或子层的hitTest:方法或者直接重载其中任一方法。响应者有时会在 事件转发之前对hitTest进行处理。 如果传入hitTest:withEvent:或hitTest:方法的触摸点位置在包括此方法的视图范围之 内,则会被忽略。也就是说子视图在其父视图的范围之外则不会收到触摸事件。 如果你自定的视图有子视图,你必须决定是否在子视图层或父视图层对触摸进行处理。 如果子视图没有声明 touchesBegan:withEvent:,touchesMoved:withEvent:或 touchesE
48、nded:withEve nt:方法对触摸进行处理,则相关的事件会传递给它的父视图。对 于多次点击或多点触摸都是与首个触摸子视图相联系,所以父视图是不会收到触摸消息的。 要确认能收到所有的触摸消息,父视图要重载hitTest:withEvent:方法并返回其自身对象而 不是其子视图。 下面的代码示例用于检测位于自定义视图层上的“info”图片何时被点击 -(void )touchesBegan:( NSSet *)touches withEvent:(UIEvent *)event CGPoint location = touches anyObject locationlnView :sel
49、f; CALayer *hitLayer = self layer hitTest:self convertPoint :location fromView :nil; if (hitLayer) self display Info ; 下面的代码,一个响应者类(在本例中为UIWindow的子类)重载了 hitTest:withEvent:方法。首先返回父类的hit-test视图,如果该视图是其本身,则返回其最 后一个子视图。 -(UIView *)hitTest:( CGPoint )point withEvent:( UIEvent *)event UIView *hitView = su
50、per hitTest :po int withEve nt :eve nt; if (hitView = self) return self subviews lastObject ; else return hitView; 转发触摸事件 事件转发是用于一些应用程序的一种技术。你通过调用另一个响应者对象的事件处理方 法将触摸事件进行转发。尽管这是个很有效率的方法,但在使用过程中还有很多需要注意的 地方。UIKit Framework中的类并不是设计用于接收不在其范围内的触摸事件,从编程的角 度来看,也就是UlTouch对象的view属性必须持有一个对framework 对象的引用以用来 对
51、触摸事件进行处理。如果你想在你的应用程序中有选择的将触摸事件传递给其它响应者, 用于接收的响应者必须是你自己定义的UIView的子类。 例如:一个应用程序有三个自定义的子视图:A,B和C。当用户点击了视图A,应用 程序的窗口对象确定所点击的视图是个hit-test视图并向其发送初始触摸事件。根据一定的 条件,视图A将事件转发给视图B或C。在这种情况下,视图A,B和C必须注意要使事 件能进行转发,视图B和C要能对不在其范围内的触摸进行处理。 事件转发经常需要分析触摸对象用来确定向何处转发事件。有些方法可以用来进行这样 的分析: 对于一个视图,使用hit-testing对事件进行分析在将其转发到子
52、视图之前 在UIWindow的自定义子类中重载sendEvent:方法,对触摸进行分析并将其转发给合 适的响应者。如果重载了该方法,你就必须调用父类的sendEvent:方法 设计你的应用其中并不需要对触摸进行分析 下面的代码示例了第二种方法,自定义一个 UIWindow的子类并对sendEvent:方法进 行重载。本例中,子类对象将触摸事件转发给一个自定义的”helper ”响应者,在该响应者 中对相应的视图进行affine变换。 -(void )sendEvent:( UIEvent *)event for (Tran sformGesture *gesturein tran sformG
53、estures) / collect all the touches we care about from the eve nt NSSet *touches = gesture observedTouchesForEve nt:eve nt; NSMutableSet *began = nil; NSMutableSet *moved = n il; NSMutableSet *ended = nil; NSMutableSet *ca ncelled =nil; / sort the touches by phase so we can han die them similarly to
54、normal eve nt dispatch for (UITouch *touch in touches) switch (touch phase ) case UlTouchPhaseBegan: if (!bega n) began = NSMutableSet set; bega n addObject:touch; break ; case UITouchPhaseMoved: if (!moved) moved = NSMutableSet set; moved addObject :touch; break ; case UITouchPhaseEnded: if (!en ded) ended = NSMutableSet set; en ded addObject :touch; break ; case UITouchPhaseCancelled: if (!ca ncelled) can celled = NSMutableSet set; ca ncelledaddObject :touch; break ; default : break ; /
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高中信息技术课堂教学方法的创新研究
- 2025光电车衣发电系统
- 中小学心理健康教育课程设计与实践知到课后答案智慧树章节测试答案2025年春浙江师范大学
- 三级人力资源管理师-三级人力资源管理师考试《理论知识》押题密卷6
- 三级人力资源管理师-《企业人力资源管理师(理论知识)》考前强化模拟卷6
- 山东省菏泽市东明县第一中学2024-2025学年高二下学期开学地理试题
- 2018高考人教政治二轮巩固练题(六)及解析
- 2018年普通高校招生全国统一考试仿真模拟(一)语文试题
- 甘肃省张掖市高台县一中2024-2025学年高三下学期第二次检测语文试题(原卷版+解析版)
- 2025届福建省漳州市高三下学期第三次检测历史试题 (原卷版+解析版)
- 临床护理技术操作常见并发症的预防与处理规范
- 《建筑施工塔式起重机安装、使用、拆卸安全技术规程》
- 风管工程量计算方法
- 2024年江苏连云港灌云县水务集团有限公司招聘笔试参考题库含答案解析
- 3×36000KVA锰硅合金直流炉1×6300KVA 精炼炉及配套 1×36000KVA富锰渣炉建设项目环评可研资料环境影响
- 《阿Q正传》《边城》联读课件 统编版高中语文选择性必修下册
- 间质性肺炎患者的护理健康评估
- 设计方案提资
- 【海信电器员工流失现状调查及其原因和完善策略10000字】
- 小学美术人教版三年级下册 .动物的花衣裳 教学课件
- 国资公司招聘总经理试题
评论
0/150
提交评论