Understanding iOS Event Handling

Source: Internet
Author: User

Write in front

One of the most recent iOS app projects encountered this problem: most of the resources that access the server through the app do not need to be logged in, but access to certain resources is required by the user to provide authentication, generally, the practice of the app (for example, the American Group app) places these resources in the "my" module, when not logged in, when clicked "My" a module, with modally to give an interface for login, I do not know how the United States Regiment is implemented, but in my opinion, the more elegant way is to implement the network at the bottom of the "modally rendering Login Interface", specifically, when users want to access "My shopping voucher", In the network access layer found that the user is not logged in, a login interface pops up, the user login successfully, the login interface to dismiss off.

The benefit of this implementation is to make the login module management more centralized and easy to maintain. Its implementation is not difficult, modally way to render a page code is very simple, as follows:

12 Uiviewcontroller *VC = [] [Uiviewcontroller alloc] init]; [Selfpresentviewcontroller:vc animated:YES Completion:nil];

This is a bit cumbersome to handle at the network layer because PresentViewController:animated:completion: is the method defined in Uiviewcontroller, so, Modally the first task of rendering a page is to know the view controller that is currently being rendered. Search "iOS get current View controller" here seems to find a better solution. So finally my key code is as follows:

123456789101112131415161718192021222324252627282930 Uiviewcontroller *result = nil; //1. Get Current WindowUIWindow * window = [[uiapplication sharedapplication] Keywindow]; if (window.windowlevel! = uiwindowlevelnormal) { Nsarray *windows = [[uiapplication sharedapplication] windows]; For (UIWindow * tmpwin in windows) { if (tmpwin.windowlevel = = uiwindowlevelnormal) { window = Tmpwin;Break ;}}} //2. Get current View Controller UIView *frontview = [[Window subviews] Objectatindex:0]; ID nextresponder = [frontview Nextresponder];if ([Nextresponder iskindofclass:[Uiviewcontroller class]]) { result = Nextresponder;}else {result = Window.rootviewcontroller;} //3. Present Login VC modally //3.1 init VC Loginnavigationcontroller *nav = [[Loginnavigationcontroller alloc] init]; //3.2 show VC [result Presentviewcontroller:nav animated:YES Completion:nil];

This code has never been validated, and today Hollow decided to make a simple analysis of this simple code. Prior to Uiresponder is not familiar with, to supplement the relevant knowledge points, I refer to the document is the official document "Event Handling Guide for IOS".

In iOS, "handling of events" is called Responder.

Hit-testing

There are various coverage relationships between views of iOS, such as View A is a subview on view B, so if a touch event is generated on view a, then does "touch event occur on a" or "touch event occurs on B"? Hit-testing is a concept that is born to solve this problem.

As for hit-testing, the official documentation describes this:

IOS uses hit-testing to find the view 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 the What 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 the" View for handling.

To describe this process using graphics, such as:

Let's assume that a user touch Event,ios hit-test process occurs on view e as follows:

    1. Touch event occurs within view A's bounds and continues to check for Subview B and Subview C;
    2. Touch event does not occur within view B's bounds, but occurs within view C's bounds, checking the Subview D and Subview E of view C;
    3. Touch event does not occur in the bounds of view d but occurs within the bounds of view e, and there is no subviews under view E, so it is determined that view E is the so-called Hit-test view.

Returning to the above citation, I read this text with a question: If view A is really a subview of view B, but the area of view a is not within the bounds of view B, for example, the touch that occurs on view a Can the event be detected?

P.S: After the author's test, get the result is not!

Add the following code to the Viewdidload method:

12345678910111213141516171819202122232425262728293031323334353637383940414243 self. View. backgroundcolor = [uicolor whitecolor]; UIView *lightgrayview = ({UIView *view = [[UIView alloc] init]; View. backgroundcolor = uicolor. Lightgraycolor; View;}); [self. View Addsubview:lightgrayview]; [Lightgrayview makeconstraints:^ (Masconstraintmaker *make) {UIView *superview = self. view; int padding = 10.0; Make. Left. Equalto (Superview. left). Offset (padding); Make.Equalto (Superview. Right). Offset (-padding); Make. Height. Equalto (Lightgrayview. width). Offset (-padding); Make. CenterY.Equalto (Superview. CenterY). Offset (0); }];UIView *yellowview = ({UIView *view = [[UIView alloc] init]; View. backgroundcolor = uicolor. Yellowcolor; View;}); [Lightgrayview Addsubview:yellowview]; [Yellowview makeconstraints:^ (Masconstraintmaker *make) {UIView *superview = Lightgrayview;Make. Width. Equalto (Superview. width). Multipliedby (0.5). Offset (0.0); Make. Height. Equalto (Yellowview. width). Offset (0.0); Make. Left. Equalto (Superview). Offset (0); Make. TopEqualto (Superview. Top). Offset (--); }];yellowview. userinteractionenabled = YES; [Yellowview Addgesturerecognizer: ({uitapgesturerecognizer *gesture =[[uitapgesturerecognizer alloc] InitWithTarget:Self Action:@selector (SayHello:)]; Gesture. numberoftapsrequired = 1; gesture;})];

P.S: The third-party AutoLayout framework Masonry is used in the code, and the results are as follows:

The yellow view is the subview of the gray view, but the yellow view is not all included in the gray view bounds, adding a tap gesture event binding to the yellow view, and the test finds that Tap event is not triggered when you click on the upper half of the yellow view (outside of its gray bounds area), but clicking on the lower half of the yellow view will trigger the touch event.

Therefore, it can be concluded that if view a is a subview of view B, but view a is not within the bounds of view B, then when view A's touch event occurs outside the bounds of view B, The response did not actually occur (or was not recognized).

In fact, the document also has a corresponding explanation:

If the point passed into hitTest:withEvent:is not inside the bounds of the view, the first call to the Pointinside:withev Ent:method returns NO, the point is ignored, and hitTest:withEvent:returns nil. If a subview returns NO, that's whole branch of the view hierarchy is ignored, because if the touch does not occur on that Su Bview, it also did not occur in any of the that Subview ' s subviews. This means, any point in a subview so is outside of its Superview can ' t receive touch events because the touch p Oint have to be within the bounds of the Superview and the Subview.

What about finding Hit-test view? Hit-test View is the first view that has the opportunity to handle touch event, and if it does not, go to the top ... This involves responder chain the concept.

The Responder Chain

responder chainis a very important concept in iOS (as opposed to Android). Before you know the concept of responder chain, you have to understand responder. The document says:

A Responder object is an object which can responder to and handle events. The Uiresponder class is the base class for all responder objects, and it defines the programmatic interface Event handling but also for common responder behavior.

UIApplication, Uiviewcontroller, and UIView instances of these classes and their subclass instances are responders.

When the iOS hit-testing found the target view that occurred, the event was transferred between responder chain, and the first responder to deal with the event was hit-testing view, of course. If it cannot handle this event, it will continue to transfer to the upper layer (such as Super view), but given that the Uiviewcontroller and UIApplication instances are also responder, it is possible to route more than just hit-testing View-super view-super view-super view-... So simple, specifically there are two delivery routes:

! [Qq20150215-2] Qq20150215-2.png

Why are there two kinds of? In fact, a little look is also very simple, the second corresponds to the view controller nesting situation.

OK, looking back at the "Get Current View Controller" code , the first part of "get" window is not a problem, the second part of the code (below) is worth pondering:

12345678 UIView *frontview = [[Window subviews] Objectatindex:0];  ID nextresponder = [frontview Nextresponder]; if ([Nextresponder iskindofclass:[Uiviewcontroller class]] {result = Nextresponder;} else {result = Window.rootviewcontroller;}

This code generally is not a problem, but it is not particularly good, because this code executes the premise that the key Windows Subview only one, and does not include other view, so I made a little bit of a change:

1234567891011 2. Get current View Controllernsarray *subviews = [window subviews]; For (UIView *view in subviews) {id nextresponder = [view Nextresponder]; if ([Nextresponder iskindofclass:[Uiviewcontroller class]] {result = Nextresponder;}} if (result = = nil) {result = Window.rootviewcontroller;}

Ok,game over! About responder, there are more "high-end" knowledge points, have encountered similar problems after that.

Reference:
Event Handling Guide for IOS

Understanding iOS Event Handling

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.