IOS Event Response Chain (Responder Chain), iosresponder

Source: Internet
Author: User

IOS Event Response Chain (Responder Chain), iosresponder

  • Overview

In iOS, the view level is generally the parent view-> Add each seed view. At this time, a view (subview) has a button that requires interaction. But sometimes we will find that no response is made in any case. At this time, it may be that we are still confused about the response to iOS events.

  • Events in iOS
  • Touch event

Response object (UIResponder)

In iOS, events can be received and processed as long as the objects that inherit UIResponder. IOS provides some methods to handle touch events.

-(Void) touchesBegan :( NSSet <UITouch *> *) touches withEvent :( nullable UIEvent *) event; // it will be called once when you start to touch the View-(void) touchesMoved :( NSSet <UITouch *> *) touches withEvent :( nullable UIEvent *) event; // it will be called multiple times as the finger moves-(void) touchesEnded :( NSSet <UITouch *> *) touches withEvent :( nullable UIEvent *) event; // call-(void) touchesCancelled :( NSSet <UITouch *> *) touches withEvent :( nullable UIEvent *) event when the finger leaves; // call this method automatically when the call comes in before the touch ends.

Event generation

When a touch event occurs, the system adds the touch event to the event queue managed by the UIApplication (first-in-first-out) -> the UIApplication extracts the first event from the event queue to distribute it, generally, send an event to the application's main window first-> the main window will find the most appropriate view to handle the touch event-> find the appropriate view control, one or more of the preceding methods of the control are called to process specific events.

Event Transfer

The main window first determines whether the touch event can be received. If not, return directly;

The main window can receive, pass to the subview, continue to judge, continue to pass, and loop until there is no child control that can meet the response, then it will be considered the most appropriate for you to handle this event.

There are also situations where responses cannot be returned:

1. Interaction not allowed

2. Hide controls

3. low transparency (<0.01)

How to find the most appropriate controls to handle events

There are two very important methods for UIView and its subclass.

- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;   // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;   // default returns YES if point is in bounds

When an event is passed to the control, the control calls

hitTest: withEvent:

The function is to find and return the most appropriate View. no matter whether the control can process the event or whether the touch point is in the space, it will first receive the event and then call the method.

So here we have the operational space, because no matter where the click event occurs, the View that can finally handle the event is the View returned by this method. By rewriting this method, we can intercept the entire event transfer process and specify the View for processing the event. (If nil is returned by this method, neither the control that calls this method nor its subcontrols can process the event. Only its parent view can process the event)

Therefore, the event Transmission sequence: generate a touch event-> UIApplication event queue-> [UIWindow hitTest: withEvent:]-> return a more appropriate View-> [subcontrol hitTest: withEvent:] -> return the most appropriate View...

Therefore, we can conclude that the hitTest method will be called when the View is not the most suitable for the pipe control. If the View is not the most suitable, nil will be returned, the parent View is also the most suitable View.

Tip: return the most suitable child control in the parent control. Because if you return yourself, two views B and C may load A at the same time. If you set B to the most appropriate View, if we return ourselves in B, maybe we click C. At this time, B has not come yet and the return system has located C.

Find the most appropriate underlying View Analysis

// When to call: as long as the event is passed to a control, the control will call its own method // function: find and return the most appropriate view // UIApplication-> [UIWindow hitTest: withEvent:] find the most appropriate view and tell the system // point: the point touched by the current finger // point: method call coordinate system point-(UIView *) hitTest :( CGPoint) point withEvent :( UIEvent *) event {// 1. determine whether the window can receive the event if (self. userInteractionEnabled = NO | self. hidden = YES | self. alpha <= 0.01) return nil; // 2. determine if the next point is not in the window // if ([self pointInside: point withEvent: event] = NO) return nil; // 3. traverse the child control array from the back to the front int count = (int) self. subviews. count; for (int I = count-1; I> = 0; I --) {// obtain the UIView * childView = self. subviews [I]; // Coordinate System Conversion, convert a vertex in the window to a vertex in the Child control // convert the vertex in the control to a vertex in the Child control CGPoint childP = [self convertPoint: point toView: childView]; UIView * fitView = [childView hitTest: childP withEvent: event]; if (fitView) {// if you can find the most suitable view return fitView;} // 4. no more suitable view is found, that is, no view return self ;}

Override the hitTest method of View to find the most suitable View.

 

Another important method

pointInside: withEvent: 

The method is used to determine whether the point position of the touch event is in the current View. If NO is returned, the event is not in the current View coordinate system and cannot be processed.

 

 

Event Response

The transfer mode is from bottom to top.

  

Event handling process

Generate a touch event-> Add an event to the UIApplication queue-> event transfer Main Window-> find the most appropriate View-> call your own touch method to handle the event-> touches by default, events are transmitted along the response chain.

// If you click the control, touchBegin is called. If you do not rewrite this method, you cannot handle the touch event-(void) touchesBegan :( NSSet *) touches withEvent :( UIEvent *) event {// by default, the event is passed to the previous responder. The previous responder is the parent control and handed over to the parent Control for processing [super touchesBegan: touches withEvent: event]; // note that the touches method of the parent control is not called, but the touches method of the parent class is called. // The superview of the parent class is the parent control}

When we need to process multiple objects of an event at the same time, we can first process our own event and then call the super method.

 

  • Instance application

When we want to expand the button clicking range

For example, if we have a 20pt * 20pt button, we can use hitTest to implement it in a control. For example, a UIButton is used to customize a button and rewrite the method in its custom class.

-(UIView *) hitTest :( CGPoint) point withEvent :( UIEvent *) event {// 1. determine whether the window can receive the event if (self. userInteractionEnabled = NO | self. hidden = YES | self. alpha <= 0.01) return nil; // click CGRect touchRect = CGRectInset (self. bounds,-20,-20); if (CGRectContainsPoint (touchRect, point) {for (UIView * subView in [self. subviews reverseObjectEnumerator]) {CGPoint convertedPoint = [subView convertPoint: point toView: self]; UIView * hitTestView = [subView hitTest: convertedPoint withEvent: event]; if (hitTestView) {return hitTestView;} return self;} return nil ;}

Pass the event to the sibling View (A and B are in the same parent View, but B Partially blocks A; click to block part A to respond to the event) at this time, clicking A will not have any response, unless the userInteractionEnable of B is NO, but we can do the same with hitTest. Rewrite this method of B.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {    UIView *hitTestView = [super hitTest:point withEvent:event];    if (hitTestView == self) {        hitTestView = nil;    }    return hitTestView;}

 

 

  

  

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.