因为UIView是UIResponder的子类,所以覆盖以下四个方法就可以处理四种不同的触摸事件:
•一根手指或多根手指触摸屏幕。
- (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;
当系统检测到手指触摸屏幕的事件后,就会创建UITouch对象(一根手指的触摸事件对应一个UITouch对象)。发生触摸事件的UIView对象会收到touchesBegan:withEvent:消息,系统传入的第一个实参touches(NSSet对象)会包含所有相关的UITouch对象。
当手指在屏幕上移动时,系统会更新相应的UITouch对象,为其重新设置对应的手指在屏幕上的位置。最初发生触摸事件的那个UIView对象会收到touchesMoved:withEvent:消息,系统传入的第一个实参touches(NSSet对象)会包含所有相关的UITouch对象,而且这些UITouch对象都是最初发生触摸事件时创建的。
当手指离开屏幕时,系统会最后一次更新相应的UITouch对象,为其重新设置对应的手指在屏幕上的位置。接着,最初发生该触摸事件的视图会收到touchesEnded:withEvent:消息。当收到该消息的视图执行完touchesEnded:withEvent:后,系统就会释放和当前事件有关的UITouch对象。
下面对UITouch对象和事件响应方法的工作机制做一个归纳。
•一个UITouch对象对应屏幕上的一根手指。只要手指没有离开屏幕,相应的UITouch对象就会一直存在。这些UITouch对象都会保存对应的手指在屏幕上的当前位置。
•在触摸事件的持续过程中,无论发生什么,最初发生触摸事件的那个视图都会在各个阶段收到相应的触摸事件消息。即使手指在移动时离开了这个视图的frame区域,系统还是会向该视图发送touchesMoved:withEvent:和touchesEnded:withEvent:消息。也就是说,当某个视图发生触摸事件后,该视图将永远“拥有”当时创建的所有UITouch对象。
•读者自己编写的代码不需要也不应该保留任何UITouch对象。当某个UITouch对象的状态发生变化时,系统会向指定的对象发送特定的事件消息,并传入发生变化的UITouch对象。
当应用发生某个触摸事件后(例如触摸开始、手指移动、触摸结束),系统都会将该事件添加至一个由UIApplication单例管理的事件队列。通常情况下,很少会出现满队列的情况,所以UIApplication会立刻分发队列中的事件。分发某个触摸事件时,UIApplication会向“拥有”该事件的视图发送特定的UIResponder消息(如果读者在执行触摸操作时感觉应用的反应迟缓,就很有可能是因为应用的某个方法占用了大量CPU时间,导致队列堵塞。第14章会介绍如何查出产生这类问题的原因)。
当多根手指在同一个视图、同一个时刻执行相同的触摸动作时,UIApplication会用单个消息、一次分发所有相关的UITouch对象。UIApplication在发送特定的UIResponder消息时,会传入一个NSSet对象,该对象将包含所有相关的UITouch对象(一个UITouch对象对应一根手指)。但是,因为UIApplication对“同一个时刻”的判断很严格,所以通常情况下,哪怕一组事件都是在很短的一段时间内发生的,UIApplication也会发送多个UIResponder消息,分批发送UITouch对象。