Hittest method
- It’s used to find the best view
- When an event is passed to a control, the control’s hitTest method is called
- Click on the white view: Touch event -> UIApplication -> UIWindow call [UIWindow hitTest] -> White View [WhteView hitTest]
Experiment 1:
Define a BaseView in which you implement a method, touchBegan, that listens for which class is currently calling the method.
Define a KeyWindow and implement a hitTest method in it that listens for which class called the method and uses it to track which view is the most appropriate view
Add 5 views of different colors on the interface of the controller, each view custom view to achieve, so the gesture on different views can be intercepted by different views.
//KeyWindow
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *view = [super hitTest:point withEvent:event];
NSLog(@"fittest->%@",view);
return view;
}
Copy the code
Results:
Click on white 1:
BrownView--hitTest withEvent 2017-10-11 16:48:52.882547+0800 Mainstream App framework [16295:358790 [16295:358790] GreenView--hitTest withEvent 2017-10-11 16:48:59.647145+0800 Mainstream App Framework [16295:358790] fittest-><UIView: 0x7f8f23406510; frame = (0 0; 414, 736); autoresize = W+H; layer = <CALayer: 0x60C000221840 >> 2017-10-11 16:48:59.647575+0800 Mainstream App Framework BrownView--hitTest withEvent 2017-10-11 [16295:358790] GreenView--hitTest withEvent 2017-10-11 16:48:59.647880+0800 Fittest -><UIView: 0x7F8F23406510; frame = (0 0; 414, 736); autoresize = W+H; layer = <CALayer: 0x60c000221840>>Copy the code
Click on blue 3:
[16295:358790] BrownView--hitTest withEvent 2017-10-11 16:49:56.331335+0800 BView--hitTest withEvent 2017-10-11 16:49:56.331617+0800 Mainstream App framework [16295:358790] BlueView--hitTest WithEvent 2017-10-11 16:49:56.331968+0800 Mainstream App framework [16295:358790] YellowView--hitTest withEvent 2017-10-11 16:49:56.333206+0800 Mainstream App framework [16295:358790] FITTest -><BlueView: 0x7F8F23406F10; frame = (19 21; 240, 128); autoresize = RM+BM; layer = <CALayer: 0x60C0002218C0 >> 2017-10-11 16:49:56.333633+0800 BrownView--hitTest withEvent 2017-10-11 [16295:358790] BView--hitTest withEvent 2017-10-11 16:49:56.333893+0800 [16295:358790] BlueView--hitTest withEvent 2017-10-11 16:49:56.334005+0800 mainstream App Framework [16295:358790] YellowView--hitTest withEvent 2017-10-11 16:49:56.334185+0800 Mainstream App framework [16295:358790] FitTest -><BlueView: 0x7F8F23406F10; frame = (19 21; 240, 128); autoresize = RM+BM; Layer = <CALayer: 0x60C0002218C0 >> 2017-10-11 16:49:56.334644+0800 Mainstream App framework [16295:358790] BlueViewCopy the code
So what hitTest does is find the most appropriate view, so we can specify the most appropriate view for anything as a particular view
Experiment 2:
If you return the BlueView from the hitTest method in the KeyWindow, clicking on any color block of view will be handed to the BlueView to handle the event.
//KeyWindow
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
return self.subviews.firstObject.subviews.firstObject;
}
Copy the code
Results:
2017-10-11 22:48:46.102793+0800 Mainstream App Framework GreenView 2017-10-11 22:48:46.668595+0800 Mainstream App Framework GreenViewCopy the code
Because the event responder chain is that when the user manipulates the screen, an event will be generated, and the event will be added to the event queue by the system. The UIApplication object will pass the earliest event added to the event queue to the Window, and then the Window will find the most appropriate view to process the event. So any event will be judged first by the KeyWindow object to find the most appropriate view
Two important ways
-
-(BOOL)pointInside:(CGPoint) Point withEvent:(UIEvent *) Event: Indicates whether the touch point is on the control
-
-(UIView *)hitTest:(CGPoint) Point withEvent:(UIEvent *)event: Used to determine whether the control accepts the event and find the most appropriate view
Imitate the system implementation to find the most appropriate view
//KeyWindow /** Echo the system implementation to find the most suitable view step 1, the control receives the event 2, the touch point on their own 3, traverses the child control from back to front, repeat the previous two steps 4, if there is no child control that meets the conditions, */ -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{if(self. UserInteractionEnabled = = NO | | the self. The hidden = = YES | | the self. The alpha < = 0.01) {return nil;
}
if(! [self pointInside:point withEvent:event]) {return nil;
}
for (NSUInteger index = self.subviews.count - 1; index >= 0; index--) {
CGPoint childViewPoint = [self convertPoint:point toView:self.subviews[index]];
UIView *fitestView = [self.subviews[index] hitTest:childViewPoint withEvent:event];
if (fitestView) {
return fitestView;
}
return nil;
}
return self;
}
Copy the code
Give a Demo address: github.com/FantasticLB…
Experiment:
Add a UIButton and then a custom UIView(ShelterView) on top of the button.
Requirement: Click on a point on the ShelterView, give it to THE UIButton if it’s also in the UIButton range, give it to the ShelterView if it’s not on the UIButton, and give it to the controller’s view if you click on a point on the screen other than the ShelterView.
//ViewController
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"viewController->%s",__func__);
}
//ShelterView
#import "ShelterView.h"
@implementation ShelterView
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"%s",__func__);
}
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
NSLog(@"%s",__func__); /** If the view is hitTest, return nil to indicate that the view is not the most suitable view, and the button is considered the most suitable viewreturnnil; */ / click on the view. If the click range is on the button, the button will handle the event. UIView *button = nil;for (UIView *subView inSelf.superview.subviews) {// Determine whether the event point is on the buttonif ([subView isKindOfClass:[UIButton class]]) {
button =subView;
}
CGPoint btnPoint = [self convertPoint:point toView:button];
if ([button pointInside:btnPoint withEvent:event]) {
return button;
}else{// this means that the touch point of the event is not on the button, but you can't write nil either. If you write nil, click somewhere else on the screen and the system will look for the most appropriate view and return nil (returnNil;) , means that the view is not the most appropriate view, then click the area on the screen except the button, the most appropriate view is the view on the controllerreturn[super hitTest:point withEvent:event]; }}return nil;
}
@end
Copy the code
To see the full Demo, github.com/FantasticLB…