iOS development-Event delivery response chain

Source: Internet
Author: User

I. Preamble

When we are using tools like this, click Sweep to open the QR Code scan view. When we clicked on the screen, the iphone OS got the user "click" Behavior, the operating system wraps the information containing these click events into Uitouch and uievent forms, and then finds the currently running program, looking for the object that can respond to the event. Until there is no responder response. This search process, called the event's response chain, as shown, is not used by the responder to look for in a chained way.
Event Response Chain:

Ii. respondents

In iOS, objects that are capable of responding to events are subclass objects of Uiresponder. Uiresponder provides four user clicks of the callback method, corresponding to the user click Start, move, click End and Cancel the click, only when the program is forced to quit or call, cancel the Click event will be called.

When customizing UIView as a base class control, we can override these methods to make a click callback. In the callback, we can see that the method receives two parameters, a collection of Uitouch objects, and a Uievent object. These two parameters represent the Click Object and the Event object respectively.

    • Event Object
      iOS uses uievent to represent the event object of user interaction, and in the UIEvent.h file, we can see that there is a Uieventtype type property that represents the current response event type. Multiple touch, shake, and remote operation (3DTouch event type added after iOS). The Uievent object is unique during a user click event process

    • Click Object
      Uitouch represents a single click that has an enumeration type Uitouchphase attribute in its class file to represent the state of the current click. These states include Click Start, move, stop, end, and cancel five states. Each time a click occurs, the Click object is placed in a collection in a callback method that passes in the Uiresponder, and we get the location of the user's click through the objects in the collection. where through-(Cgpoint) Locationinview: (Nullable UIView ) View gets the current click Coordinate Point,-(Cgpoint) Previouslocationinview: (Nullable UIView ) View gets the coordinate point of the last click position.

In order to confirm that UIView is actually responding to the Click event via Uiresponder, I created the UIView category and rewritten the + (void) Load method to exchange the implementation of the Click event using the Method_swizzling way

+ (void) Load{Method origin = Class_getinstancemethod ([UIViewClass],@selector(touchesbegan:withevent:)); Method custom = Class_getinstancemethod ([UIViewClass],@selector(lxd_touchesbegan:withevent:));    Method_exchangeimplementations (origin, custom); Origin = Class_getinstancemethod ([UIViewClass],@selector(touchesmoved:withevent:)); custom = Class_getinstancemethod ([UIViewClass],@selector(lxd_touchesmoved:withevent:));    Method_exchangeimplementations (origin, custom); Origin = Class_getinstancemethod ([UIViewClass],@selector(touchesended:withevent:)); custom = Class_getinstancemethod ([UIViewClass],@selector(lxd_touchesended:withevent:)); Method_exchangeimplementations (origin, custom);} - (void) Lxd_touchesbegan: (Nsset *) touches withevent: (uievent *) event{NSLog(@"%@---begin", Self. Class); [ SelfLxd_touchesbegan:touches withevent:event];} - (void) lxd_touchesmoved: (Nsset *) touches withevent: (uievent *) event{NSLog(@"%@---move", Self. Class); [ SelfLxd_touchesmoved:touches withevent:event];} - (void) lxd_touchesended: (Nsset *) touches withevent: (uievent *) event{NSLog(@"%@---end", Self. Class); [ SelfLxd_touchesended:touches withevent:event];}

In the new project, I created the subclasses of Aview, Bview, CView, and Dview four UIView respectively, and then click anywhere:

When I click on the Green view, the console outputs the following log (the date part has been removed):

    CViewbegin    CViewend

This shows that when we click on UIView, the callback is handled by touches related click events.

In addition to several click events for the touches callback, gesture Uigesturerecognizer objects can also be attached to the view to implement other rich gesture events. After you add a click gesture to a view, the original touchesended method is invalid. At first I always thought that after the view added gesture, the original touches series methods were all invalid. But in the test demo, after the view added gesture, the Touchesbegan method has a callback, but moved and ended do not have a callback. Therefore, in the system's touches event processing, after Touchesbegan, there should be a scheduling follow-up event (Nexthandler) processing method, the personal guessing event scheduling processing is as follows:

Third, response chain delivery

Customize a view, by Method-(Nullable Uiresponder *) Nextresponder, through the method name we are not difficult to find that this is the next responder to get the current view, then we rewrite the Touchesbegan method to get the next responder Until there is no next responder location. The relevant code is as follows:

-(void)Touchesbegan:(Nsset<Uitouch*> *) toucheswithevent:(uievent*) event{Uiresponder*Next= [ SelfNextresponder];nsmutablestring* prefix = @"". mutablecopy; while(Next!=Nil) {NSLog(@"%@%@", prefix, [Next  class]);[PrefixappendString:@"--"];Next= [NextNextresponder]; }}

Print:

    AView    --UIView    ----ViewController    ------UIWindow    --------UIApplication    ----------AppDelegate

Although the results are very hierarchical, the order of the output is reversed from the point of view of the system's stepwise search for the responder. Why does this problem occur? We can see that there is a Viewcontroller class in the output, stating that Uiviewcontroller is also a subclass of Uiresponder. But we can find that the controller is a view manager, even if it is a member of the response chain, but according to logic, controllers should not be one of the system lookup objects, through the Nextresponder method to find this idea is not correct.

The following two methods:

-(Nullable UIView *)hitTest:(cgpoint) point withevent:(Nullable uievent *) event; // recursively calls-pointinside:withevent:. Point was  in the receiver' s coordinate system -(BOOL)pointinside:(cgpoint) point withevent:(Nullable uievent *) Event // default returns YES If point was  in bounds;

Depending on the method name, one is whether the event occurs in this view based on the click Coordinates, and the other method is to return the object that responds to the Click event. With these two methods, we can guess that the system gets the view of the next response by continually iterating through these methods of the child view on the current view when it receives the Click event. Therefore, the implementation of these two methods continues to be modified by the Method_swizzling method, and the test output is as follows:

Uistatusbarwindow can answer1Uistatusbar can answer0Uistatusbarforegroundview can answer0Uistatusbarserviceitemview can answer0Uistatusbardatanetworkitemview can answer0Uistatusbarbatteryitemview can answer0Uistatusbartimeitemview can answer0Hit View:uistatusbar hit View:uistatusbarwindowUIWindowCan answer1    UIViewCan answer1Hit view: _uilayoutguide hits View: _uilayoutguide Aview can answer1DView can answer0Hit View:dview bview can answer0Hit View:bview hits View:aview hit view:UIViewHit View:UIWindow......///The following is the output of the touches method

The top uistatusbar of the beginning of the type you may not have seen, but it does not prevent us from guessing this is a few of the status bar related views, you can find Apple's Document Center (Xcode shortcut key shift+command+0 Open). It is not difficult to see from the output that the system calls Pointinside:withevent first: Determine whether the current view and the child views of these views can receive this click event, and then call Hittest:withevent: Get all the view objects that handle this event in turn, After getting all the processing event objects, start invoking the touches callback method of these objects;

With the output method call, we can see that the order of response lookups is: Uistatusbar related views, UIWindow, UIView, Aview->dview Bview (the system will certainly traverse all the sub-views in the event chain transfer to determine whether or not to respond to click events), in this example, we can conclude that the event response chain lookup is as follows:

Then after the lookup responder process is complete, the system will convert the clicks in this event into Uitouch objects, and then pass these objects and event objects of type Uievent to the Touchesbegan method, you

Not only that, but from the nextresponder output above, all responders return a view that responds to clicks in the lookup. Therefore, we can infer that the UIApplication object maintains its own responder stack, and when pointinside:withevent: returns Yes, the responder is in the stack.

The responder at the top of the stack acts as the object of highest priority, assuming that the Aview does not handle the event, then the stack is handed over to UIView, so that it continues until the event is processed or arrives at Appdelegate and remains unresponsive until the event is discarded. With this mechanism we can also see that the controller is an exception in the responder stack, and even if no pointinside:withevent: The method returns to be responsive, the controller can still be in the stack to become the next responder for UIView.

IV. application of the response chain

Now that we know how the system gets the flow of the response view, we can implement irregular shape clicks by overriding the method of finding the event handler. The most common irregular view is a circular view, in which I set the view's width height to 200, then the override method event is as follows:

 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{    constCGFloat100;    CGFloat xOffset = point.x100;    CGFloat yOffset = point.y100;    CGFloat radius = sqrt(xOffset * xOffset + yOffset * yOffset);    return radius <= halfWidth;}

The final is as follows:

iOS development-Event delivery response chain

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.