响应链和UIKit框架

Event Delivery: The Responder Chain

When you design your app, it’s likely that you want to respond to events dynamically. For example, a touch can occur in many different objects onscreen, and you have to decide which object you want to respond to a given event and understand how that object receives the event.

When a user-generated event occurs, UIKit creates an event object containing the information needed to process the event. Then it places the event object in the active app’s event queue. For touch events, that object is a set of touches packaged in a UIEvent object. For motion events, the event object varies depending on which framework you use and what type of motion event you are interested in.

An event travels along a specific path until it is delivered to an object that can handle it. First, the singleton  UIApplication object takes an event from the top of the queue and dispatches it for handling. Typically, it sends the event to the app’s key window object, which passes the event to an initial object for handling. The initial object depends on the type of event.

  • Touch events. For touch events, the window object first tries to deliver the event to the view where the touch occurred. That view is known as the hit-test view. The process of finding the hit-test view is called hit-testing, which is described in Hit-Testing Returns the View Where a Touch Occurred.
  • Motion and remote control events. With these events, the window object sends the shaking-motion or remote control event to the first responder for handling. The first responder is described in The Responder Chain Is Made Up of Responder Objects.

The ultimate goal of these event paths is to find an object that can handle and respond to an event. Therefore, UIKit first sends the event to the object that is best suited to handle the event. For touch events, that object is the hit-test view, and for other events, that object is the first responder. The following sections explain in more detail how the hit-test view and first responder objects are determined.

Hit-Testing Returns the View Where a Touch Occurred

iOS uses hit-testing to find the view that is under a touch. Hit-testing involves checking whether a touch is within the bounds of any relevant view objects. If it is, it recursively checks all of that view’s subviews. The lowest view in the view hierarchy that contains the touch point becomes the hit-test view. After iOS determines the hit-test view, it passes the touch event to that view for handling.

To illustrate, suppose that the user touches view E in Figure 2-1. iOS finds the hit-test view by checking the subviews in this order:

  1. The touch is within the bounds of view A, so it checks subviews B and C.
  2. The touch is not within the bounds of view B, but it’s within the bounds of view C, so it checks subviews D and E.
  3. The touch is not within the bounds of view D, but it’s within the bounds of view E.

    View E is the lowest view in the view hierarchy that contains the touch, so it becomes the hit-test view.

Figure 2-1  Hit-testing returns the subview that was touched

The hitTest:withEvent: method returns the hit test view for a given CGPoint and UIEvent. The hitTest:withEvent: method begins by calling the pointInside:withEvent: method on itself. If the point passed into hitTest:withEvent: is inside the bounds of the view, pointInside:withEvent: returns YES. Then, the method recursively calls hitTest:withEvent: on every subview that returns YES.

If the point passed into hitTest:withEvent: is not inside the bounds of the view, the first call to the pointInside:withEvent: method returns NO, the point is ignored, and hitTest:withEvent: returns nil. If a subview returns NO, that whole branch of the view hierarchy is ignored, because if the touch did not occur in that subview, it also did not occur in any of that subview’s subviews. This means that any point in a subview that is outside of its superview can’t receive touch events because the touch point has to be within the bounds of the superview and the subview. This can occur if the subview’s clipsToBounds property is set to NO.

Note: A touch object is associated with its hit-test view for its lifetime, even if the touch later moves outside the view.

The hit-test view is given the first opportunity to handle a touch event. If the hit-test view cannot handle an event, the event travels up that view’s chain of responders as described in The Responder Chain Is Made Up of Responder Objects until the system finds an object that can handle it.

The Responder Chain Is Made Up of Responder Objects

Many types of events rely on a responder chain for event delivery. The responder chain is a series of linked responder objects. It starts with the first responder and ends with the application object. If the first responder cannot handle an event, it forwards the event to the next responder in the responder chain.

responder object is an object that can respond to and handle events. The UIResponder class is the base class for all responder objects, and it defines the programmatic interface not only for event handling but also for common responder behavior. Instances of the UIApplicationUIViewController, and UIViewclasses are responders, which means that all views and most key controller objects are responders. Note that Core Animation layers are not responders.

The first responder is designated to receive events first. Typically, the first responder is a view object. An object becomes the first responder by doing two things:

  1. Overriding the canBecomeFirstResponder method to return YES.
  2. Receiving a becomeFirstResponder message. If necessary, an object can send itself this message.

Note: Make sure that your app has established its object graph before assigning an object to be the first responder. For example, you typically call the becomeFirstResponder method in an override of the viewDidAppear: method. If you try to assign the first responder in viewWillAppear:, your object graph is not yet established, so the becomeFirstResponder method returns NO.

Events are not the only objects that rely on the responder chain. The responder chain is used in all of the following:

  • Touch events. If the hit-test view cannot handle a touch event, the event is passed up a chain of responders that starts with the hit-test view.
  • Motion events. To handle shake-motion events with UIKit, the first responder must implement either the motionBegan:withEvent: or motionEnded:withEvent: method of the UIResponder class, as described in Detecting Shake-Motion Events with UIEvent.
  • Remote control events. To handle remote control events, the first responder must implement the remoteControlReceivedWithEvent: method of the UIResponder class.
  • Action messages. When the user manipulates a control, such as a button or switch, and the target for the action method is nil, the message is sent through a chain of responders starting with the control view.
  • Editing-menu messages. When a user taps the commands of the editing menu, iOS uses a responder chain to find an object that implements the necessary methods (such as cut:copy:, and paste:). For more information, see Displaying and Managing the Edit Menu and the sample code project, CopyPasteTile.
  • Text editing. When a user taps a text field or a text view, that view automatically becomes the first responder. By default, the virtual keyboard appears and the text field or text view becomes the focus of editing. You can display a custom input view instead of the keyboard if it’s appropriate for your app. You can also add a custom input view to any responder object. For more information, see Custom Views for Data Input.

UIKit automatically sets the text field or text view that a user taps to be the first responder; Apps must explicitly set all other first responder objects with the becomeFirstResponder method.

The Responder Chain Follows a Specific Delivery Path

If the initial object—either the hit-test view or the first responder—doesn’t handle an event, UIKit passes the event to the next responder in the chain. Each responder decides whether it wants to handle the event or pass it along to its own next responder by calling the nextResponder method.This process continues until a responder object either handles the event or there are no more responders.

The responder chain sequence begins when iOS detects an event and passes it to an initial object, which is typically a view. The initial view has the first opportunity to handle an event. Figure 2-2 shows two different event delivery paths for two app configurations. An app’s event delivery path depends on its specific construction, but all event delivery paths adhere to the same heuristics.

Figure 2-2  The responder chain on iOS

For the app on the left, the event follows this path:

  1. The initial view attempts to handle the event or message. If it can’t handle the event, it passes the event to its superview, because the initial view is not the top most view in its view controller’s view hierarchy.
  2. The superview attempts to handle the event. If the superview can’t handle the event, it passes the event to its superview, because it is still not the top most view in the view hierarchy.
  3. The topmost view in the view controller’s view hierarchy attempts to handle the event. If the topmost view can’t handle the event, it passes the event to its view controller.
  4. The view controller attempts to handle the event, and if it can’t, passes the event to the window.
  5. If the window object can’t handle the event, it passes the event to the singleton  app object.
  6. If the app object can’t handle the event, it discards the event.

The app on the right follows a slightly different path, but all event delivery paths follow these heuristics:

  1. A view passes an event up its view controller’s view hierarchy until it reaches the topmost view.
  2. The topmost view passes the event to its view controller.
  3. The view controller passes the event to its topmost view’s superview.

    Steps 1-3 repeat until the event reaches the root view controller.

  4. The root view controller passes the event to the window object.
  5. The window passes the event to the app object.

1、寻找响应消息视图的过程可以用一张图来说明。

处理原理如下:

• 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中

• UIApplication会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件给应用程序的主窗口(UIWindow)

• 主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的UIView来处理触摸事件

(hitTest:withEvent:其实是UIView的一个方法,UIWindow继承自UIView,因此主窗口UIWindow也是属于视图的一种)

• hitTest:withEvent:方法大致处理流程是这样的:

首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:

? 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil

? 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕:

? 若第一次有子视图的hitTest:withEvent:方法返回非空对象,则当前视图的hitTest:withEvent:方法就返回此对象,处理结束

? 若所有子视图的hitTest:withEvent:方法都返回nil,则当前视图的hitTest:withEvent:方法返回当前视图自身(self)

UIKit/框架的类继承图:

一.responder对象

在iOS系统中,能够响应并处理事件的对象称之为responder object, UIResponder是所有responder对象的基类,在UIResponder类中定义了处理各种事件,包括触摸事件(Touch Event)、运动事件(Motion Event)和远程控制事件(Remote-Control Events)的编程接口,其中处理触摸事件(Touch Event)的编程接口如下:
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
这四个方法分别处理触摸开始事件,触摸移动事件,触摸终止事件,以及触摸跟踪取消事件。

UIApplicationUIViewController,UIView和所有继承自UIView的UIKit类(包括UIWindow,继承自UIView)都直接或间接的继承自UIResponder,所以它们的实例都是responder object对象,都实现了上述4个方法。UIResponder中的默认实现是什么都不做,但UIKit中UIResponder的直接子类(UIView,UIViewController…)的默认实现是将事件沿着responder chain继续向上传递到下一个responder,即nextResponder。所以在定制UIView子类的上述事件处理方法时,如果需要将事件传递给next responder,可以直接调用super的对应事件处理方法,super的对应方法将事件传递给next responder,即使用

[super touchesBegan:touches withEvent:event];

不建议直接向nextResponder发送消息,这样可能会漏掉父类对这一事件的其他处理。

[self.nextResponder  touchesBegan:touches withEvent:event];

另外,在定制UIView子类的事件处理方法时,如果其中一个方法没有调用super的对应方法,则其他方法也需要重写,不使用super的方法,否则事件处理流程会很混乱。

时间: 2024-11-05 19:04:16

响应链和UIKit框架的相关文章

UIKit 框架之UIView二

下面这些都是UIView一些基本的东西,具体的可以参考UIKit 框架之UIView一博客 一.自定义一个View // // MyView.m // UIView // // Created by cyw on 15-5-17. // Copyright (c) 2015年 cyw. All rights reserved. // #import "MyView.h" @implementation MyView - (id)initWithFrame:(CGRect)frame {

ios中事件的响应链(Responder chain)和传递链

事件的响应链涉及到的一些概念 UIResponder类,是UIKIT中一个用于处理事件响应的基类.窗又上的所有事件触发,都由该类响应(即事件处理入又).所以,窗又上的View及控制器都是 派生于该类的,例如UIView.UIViewController等. 调用UIResponder类提供的方法或属性,我们就可以捕捉到窗又上的所有响应 事件,并进行处理. 响应者链条是由多个响应者对象连接起来的链条,其中响应者对象是能处理事 件的对象,所有的View和ViewController都是响应者对象,利

UIKit框架各个类的简介

1.UIAcceleration: 被叫做加速事件的一个UIAcceleration类的实例是用来代表即时的三维加速数据.为了接收重力加速度,要注册一个应用应用程序作为一个共享UIAccelerater对象的委托对象(参考UIAcceleromete类). 2. UIAccelerater: UIAccelerater类可以让你的寄存器接收到从板载硬件上得到的加速相关数据.当设备移动时,它的硬件能够报告沿主线在三维空间中的线性加速度变化.你可以利用这些数据来检测器件的电流方向和该方向的瞬时变化.

事件分发&响应链

iOS的三种事件:触摸事件/运动事件/远程控制事件 [objc] view plaincopy typedef enum { UIEventTypeTouches, UIEventTypeMotion, UIEventTypeRemoteControl, } UIEventType; 只有继承UIResponder类的对象才能处理事件,如UIView.UIViewController.UIApplication都继承自UIResponder,都能接收并处理事件.UIResponder中定义了上面

iOS UIKit框架

1. 简介: UIKitk框架提供一系列的Class(类)来建立和管理iPhone OS应用程序的用户界面( UI )接口.应用程序对象.事件控制.绘图模型.窗口.视图和用于控制触摸屏等的接口.(PS1: 可以认为是操纵界面的一个API库)(PS2: UIKit框架是用在iOS平台上与之对应的是MAC OS X上的Application Kit,二者是姐妹框架,作用和目的没啥太大区别(我没有说实现目的的过程也一样),表混淆了) 2. 框架的入口: #import <UIKit/UIKit.h>

iOS端JSON转Model链式编程框架SuperKVC使用方法与原理

背景 在client编程中.字典转模型是一个极为常见的问题,苹果提供了KVC来实现NSDictionary到Model的注入,可是KVC仅仅能进行单层浅注入.且无法处理类型转换.key与属性名不正确应.深度注入等问题,笔者从Masonry得到启示,开发了一个通过链式配置注入器实现深度注入.类型转换.key-属性名映射等功能的轻量级注入框架SuperKVC.眼下已经开源到GitHub,点击这里前往.欢迎Star和Fork.欢迎和我一起完好这个框架! 本文将从应用和原理两个角度介绍SuperKVC

什么是事件响应链

对于IOS设备用户来说,他们操作设备的方式主要有三种:触摸屏幕.晃动设备.通过遥控设施控制设备.对应的事件类型有以下三种: 触屏事件(Touch Event) 运动事件(Motion Event) 远端控制事件(Remote-Control Event) 响应者链(Responder Chain) 响应者对象(Responder Object),指的是有响应和处理事件能力的对象.响应者链就是由一系列的响应者对象构成的一个层次结构. UIResponder是所有响应对象的基类,在UIRespond

iOS学习9_事件分发&amp;响应链&amp;android转iOS的感悟

iOS的三种事件:触摸事件/运动事件/远程控制事件 typedef enum { UIEventTypeTouches, UIEventTypeMotion, UIEventTypeRemoteControl, } UIEventType; 只有继承UIResponder类的对象才能处理事件,如UIView.UIViewController.UIApplication都继承自UIResponder,都能接收并处理事件.UIResponder中定义了上面三类事件相关的处理方法: 下面主要讨论触摸事

iOS事件响应链

@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css); 事件传递之响应链 当你设计App时你可能需要动态的响应事件.例如,一个触摸事件可能发生在屏幕上不同的对象中,你需要决定哪个对象来响应这个给定的事件,理解对象如何接收事件. 当用户触发的一个事件发生,UIKit会创建一个包含要处理的事件信息的事件对象.然后她会将事件对象