Event delivery response chain _ios for IOS development

Source: Internet
Author: User

When we use micro-letters and other tools, click Sweep, you can open two-dimensional Code scan view. When we clicked on the screen, the iphone OS captured the user's "click" Behavior, and the operating system packaged the information that contained these click events into Uitouch and uievent forms, and then found the currently running program, looking for an object that could respond to the event. Until there is no responder response. This search process, called the event response chain, is shown in the following figure, and the unused responder looks in a chained fashion

Event response Chain

First, respondents

In iOS, objects that respond to events are Uiresponder objects of the class. Uiresponder provides four user-clicked callback methods, respectively, corresponding to the user clicks Start, move, click to end and cancel the click, which only when the program is forced to quit or call, the cancellation event will be invoked.

Uiresponder's Click event

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. The two parameters represent the Click Object and the Event object respectively.

1, Event object
iOS uses Uievent to represent event objects for user interaction. In the UIEvent.h file, we can see that there is a uieventtype type of property that represents the current response event type. There are multi-touch, rocking, and remote operations (3DTouch event types are added after iOS). During a user Click event Processing, the Uievent object is the only
2, click Object
Uitouch to indicate a single click, An enumeration type Uitouchphase attribute exists in its class file to indicate the state of the current click. These states include Click Start, move, stop, end, and cancel five states. Each time a click occurs, the object is placed in a callback method in a collection that is passed into the Uiresponder, where we get the user's click by the object in the collection. Which passes-(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.
to confirm that UIView did respond to click events through the Uiresponder click Method, I created the UIView category and overridden The + (void) Load method to swap the implementation of the Click event in method_swizzling mode

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

In the new project, I created a subclass of the Aview, bview, CView, and Dview four UIView, and then clicked Anywhere:

Project Structure Chart

When I clicked on the green view above, the console output the following log (the date part has been removed):

CView---Begin
CView---End

This shows that when we click on the UIView, it is through the touches related click event for callback processing.

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

Event scheduling

Second, response chain delivery

The above has already described a control to receive the Click event Processing, then how the system through the user clicks the location to find the processing click event View?
As we have already said, the system responds to the Click event by constantly looking for the next responder, and all the interoperable controls are uiresponder direct or indirect subclasses, so can we find the key attributes in the header file of this class?

There is just one way to do this:-(nullable Uiresponder *) Nextresponder, by means of the method name we can easily 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 *) touches withevent: (Uievent *) event
{
  Uiresponder * next = [self nextresponder];< c3/>nsmutablestring * prefix = @ "". Mutablecopy;
 
  while (next!= nil) {
    NSLog (@ "%@%@", prefix, [next class]);
    [Prefix appendstring: @ "--"];
    Next = [Next Nextresponder];
  }  

All subordinate event responders for console output are as follows:

Aview
--uiview
----viewcontroller
------uiwindow
--------uiapplication
---------- Appdelegate

Although the results are very hierarchical, the order of the output is exactly the opposite of the way the system is looking for the responder. Why is there such a problem? We can see that there is a Viewcontroller class in the output, stating that Uiviewcontroller is also a uiresponder subclass. But we can see that controller is the manager of a view, even if it is one of the members of the response chain, but logically, the controller should not be one of the system lookup objects, the idea of finding through the Nextresponder method is not correct.

Later, it was found that there were two methods in the header file for UIView to return the UIView and bool types:

-(Nullable UIView *) HitTest: (cgpoint) point withevent: (Nullable uievent *) event;  Recursively calls-pointinside:withevent:. The receiver ' s coordinate system
-(BOOL) Pointinside: (cgpoint) point withevent: (Nullable uievent *) event;  //default returns YES in bounds

Depending on the method name, one returns whether the event occurs in this view according to the click Coordinate, and the other method is to return the object that responds to the Click event. By using these two methods, we can guess that the system gets a view of the next response by constantly traversing these methods of the child view on the current view when it receives the Click event. Therefore, the implementation of the two methods continues to be modified in a method_swizzling manner, and the test output is as follows:

Uistatusbarwindow can answer 1
uistatusbar can answer 0
Uistatusbarforegroundview can answer 0
Uistatusbarserviceitemview can answer 0
Uistatusbardatanetworkitemview can answer 0
Uistatusbarbatteryitemview can answer 0
Uistatusbartimeitemview can answer 0
hit View:uistatusbar
hit view : Uistatusbarwindow
UIWindow can answer 1
uiview can answer 1
hit view: _uilayoutguide hit
view: _uila Youtguide
Aview can answer 1
dview can answer 0
hit View:dview
bview can answer 0
hit View:bvie W
hit View:aview
hit View:uiview
hit View:uiwindow
...//The following is the output of the touches method

The first type of the top Uistatusbar you may not have seen it, but it doesn't prevent us from guessing. This is a status bar-related view that can be found in the Apple Documentation Center (shortcut key shift+command+0 on Xcode). It's easy to see from the output that the system calls Pointinside:withevent first: Determine whether the current view and the child views of those views can receive this click event, and then call Hittest:withevent: sequentially get all the view objects that handle this event, Start calling the touches callback method of these objects after fetching all the handle event objects

By means of the output method call, we can see the order of response lookup is: Uistatusbar related views-> uiwindow-> uiview-> aview-> dview-> the bview (System in the process of passing the event chain must Iterates through all the child views to see if they can respond to the click event, as an example of this demo, we can draw the following diagram of the event response chain lookup:

Responder Lookup Process

Then after the lookup responder process is complete, the system converts the clicks in this event to Uitouch objects and then passes these objects and Uievent type event objects to the Touchesbegan method.

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

Responder Stack

Top of the stack of respondents as the highest priority to deal with the object of events, assuming that Aview do not handle events, then the stack, handed over to UIView, to go on, until the event has been processed or arrived appdelegate still not response, the incident was abandoned so far. Through this mechanism we can also see that controller is the exception in the responder stack, even if there is no Pointinside:withevent: The method returns the response, controller can still be able to stack into the uiview of the next responder.

three . Response Chain Application

Now that you know how the system gets the process of responding to views, we can implement irregular shape clicks by rewriting the method of finding event handlers. The most common irregular view is the circular view, in the demo I set the view width to 200, then the overriding method event is as follows:

-(BOOL) Pointinside: (cgpoint) point withevent: (Uievent *) event
{
  const cgfloat = m;
  CGFloat xoffset = point.x-100;
  CGFloat yoffset = point.y-100;
  CGFloat radius = sqrt (xoffset * xoffset + yoffset * yoffset);
  return radius <= Halfwidth
}

The final effect figure is as follows:

The above is the entire content of this article, I hope to help you learn.

Related Article

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.