Understanding Event Handling, Responders, and the Responder Chain。
了解事件处理,响应者以及响应者链。
Learn how events are propagated through your app and how you handle them.
学会事件在你的APP中是怎样传递以及你怎样处理它们。
Overview
综述
Apps receive and handle events using responder objects. A responder object is any instance of the UIResponder class, and common subclasses include UIView,UIViewController, andUIApplication. Responders receive the raw event data and must either handle the event or forward it to another responder object. When your app receives an event, UIKit automatically directs that event to the most appropriate responder object, known as thefirst responder. Unhandled events are passed from responder to responder in the active responder chain, which is a dynamic configuration of your app’s responder objects. There is no single responder chain within your app. UIKit defines default rules for how objects are passed from one responder to the next, but you can always change those rules by overriding the appropriate properties in your responder objects.Figure 1shows the default responder chains in an app whose interface contains a label, a text field, a button, and two background views. If the text field does not handle an event, UIKit sends the event to the text field’s parentUIView object, followed by the root view of the window. From the root view, the responder chain diverts to the owning view controller before directing the event to the window. If the window does not handle the event, UIKit delivers the event to the UIApplication object, and possibly to the app delegate if that object is an instance of UIResponder and not already part of the responder chain.
APP用响应对象来接收和处理事件。响应对象是UIResponder类的任何一个实例,普通的子类包括UIView,UIViewController, 和UIApplication。响应者接收到原始事件数据后,必须要么处理这个事件,要么转发给另一个响应者对象。当你的APP接收到一个事件的时候,UIKit会自动把事件指给最合适的响应者对象,称为第一响应者。在响应链条上,未处理的事件被传递从一个响应者到另一个响应者,这是你的APP响应者对象中的一个动态结构。你的程序没有单一响应者链。UIKit定义了一套默认的关于一个响应者是怎样传递给下一个响应者的规则。但是,你也可以通过重写响应者对象合适的属性来改变这个规则。下图展示了在一个APP的交互包括a label, a text field, a button, 和 two background views的默认响应者链。如果text field不能处理事件,UIKit将会发送时间给它的text field的父视图,紧接着是这个窗口的根视图。从这个根视图开始,响应者链在传到window之前会转到自己的控制器。如果window也不能处理这个事件,UIKit会把事件传递给UIApplication对象,也可能到达app delegate。如果这个对象不是UIResponder的实例,将不会称为响应链的一部分。
Determining the First Responder for an Event
For every type of event, UIKit designates a first responder and sends the event to that object first. The first responder varies based on the type of event.
对于没类型事件,UIKit都会指定第一响应者,首先发送事件到这个对象。第一响应者基于事件的类型而不同。
Touch events
触摸事件
The first responder is the view in which the touch occurred.
第一响应者是你触摸的那个视图。
Press events
按压事件
The first responder is the responder that has focus.
第一响应者是按压的响应者。
Controls communicate directly with their associated target object using action messages. When the user interacts with a control, the control calls the action method of its target object—in other words, it sends an action message to its target object. Action messages are not events, but they may still take advantage of the responder chain. When the target object of a control is nil, UIKit starts from the target object and walks the responder chain until it finds an object that implements the appropriate action method. For example, the UIKit editing menu uses this behavior to search for responder objects that implement methods with names likecut(_:),copy(_:), orpaste(_:).
控件直接使用action消息与和控件结合的target对象进行交流。当用户和控件交流的时候,控件会调用target对象的action方法。换句话说,控件会发送action消息给target对象。Action消息不是事件,但是action一直利用响应链。当控件的target对象是nil的时候,UIKit会从target对象开始,沿着响应者链,直到发现一个对象,它实现了合适的action方法。例如,UIKit编辑按钮利用这种行为来搜索实现了剪切,复制,粘贴方法的响应者。
If a view has an attached gesture recognizer, the gesture recognizer receives touch and press events before the view receives them. If all of the view’s gesture recognizers fail to recognize their gestures, the events are passed to the view for handling. If the view does not handle them, UIKit passes the events up the responder chain. For more information about using gesture recognizer’s to handle events, seeHandling UIKit Gestures.
如果给一个视图添加了一个手势,那么在视图接收到它们之前,手势会收到触摸事件。如果一个视图的所有手势都不能响应这个手势,那么事件会传递给视图进行处理。如果视图不能处理事件,UIKit传递这个事件到响应链。
Determining Which Responder Contained a Touch Event
决定哪一个响应者包含触摸事件。
UIKit uses view-based hit-testing to determine where touch events occur. Specifically, UIKit compares the touch location to the bounds of view objects in the view hierarchy. The hitTest(_:with:) method of UIView walks the view hierarchy, looking for the deepest subview that contains the specified touch. That view becomes the first responder for the touch event.
UIKit利用基view的hit-testing方法来决定触摸事件发生在哪里。具体来说,在视图层次上,UIKit将触摸位置和视图对象的边界进行比较。视图的hitTest(_:with:)方法来查找包含触摸点的最深的子视图。
Note
注意:
If a touch location is outside of a view’s bounds, the hitTest(_:with:)method ignores that view and all of its subviews. As a result, when a view’s clipsToBounds property is false, subviews outside of that view’s bounds are not returned even if they happen to contain the touch. For more information about the hit-testing behavior, see the discussion of thehitTest(_:with:)method inUIView.
如果一个触摸点在一个视图的边界外边,那么,hitTest(_:with:)方法会忽略那个视图和所有的子视图。因此,当一个视图的clipsToBounds属性是false的时候,子视图在视图外边是不能返回的,尽管视图包含触摸事件。
注意:查找触摸点的时候是以bounds为标准进行查找的。
UIKit permanently assigns each touch to the view that contains it. UIKit creates each UITouch object when the touch first occurs, and it releases that touch object only after the touch ends. As the touch location or other parameters change, UIKit updates theUITouchobject with the new information. The only property that does not change is the containing view. Even when the touch location moves outside the original view, the value in the touch’sviewproperty does not change.
UIKit会永久分配每个触摸到包含它的视图。当触摸事件发生的时候,UIKit创建UITouch对象。当触摸结束的之后,它会release掉这个对象。当触摸位置改变或者参数发生改变的时候,UIKit会用新信息更新UITouch对象。仅有的属性不会发生变化的是包含的视图。尽管当触摸位置移动到原始位置之外,触摸的视图属性并不会发生变化。
Altering the Responder Chain
变更响应者链
You can alter the responder chain by overriding thenextproperty of your responder objects. When you do this, the next responder is the object that you return.
你可以通过重写响应对象的下一个属性来改变响应者链。当你这样做之后,下一个响应者链僵尸你返回的那个。
Many UIKit classes already override this property and return specific objects.
大多数UIKit类总是重写这个属性,返回特定的对象。
UIView objects:
If the view is the root view of a view controller, the next responder is the view controller; otherwise, the next responder is the view’s superview.
UIView对象:如果这个视图是控制器的根view,下一个响应者就是控制器。否则,下个响应者是这个使徒的父视图。
UIViewController objects
控制器对象
If the view controller’s view is the root view of a window, the next responder is the window object.
如果这个控制器的视图是窗口的根视图,下一个响应者是window对象。
If the view controller was presented by another view controller, the next responder is the presenting view controller.
如果这个控制器由另一个控制器呈现,下一个响应者是这个呈现控制器。
UIWindow objects
窗口对象
The window's next responder is the UIApplication object.
窗口的想一个响应者是UIApplication。
UIApplication object:
The next responder is the app delegate, but only if the app delegate is an instance of UIResponder and is not a view, view controller, or the app object itself.
UIApplication的下一个响应者是UIApplication的代理,但是只有这个代理是UIResponder的实例,不是view,控制器,APP本身。