HitTest and pointInside methods and exercises, hittestpointinside
The role of these two methods: Find the most suitable View
1. hitTest Method
Parameter: the point where the current finger is located and the event generated
Returned value: Who is returned, and who is the most suitable View.
When to call: when an event is passed to a control, the hitTest method of the control is called.
-(UIView *) hitTest :( CGPoint) point withEvent :( UIEvent *) event
2. pointInside Method
Purpose: Determine whether the point is not on the method caller.
Point: Must be the coordinate system of the method caller
When to call: the bottom layer of the hitTest method calls this method, and the judgment point is not on the control.
-(BOOL) pointInside :( CGPoint) point withEvent :( UIEvent *) event {
Return YES;
}
3. hitTest underlying implementation:
// 1. Determine whether the current event can be received
If (self. userInteractionEnabled = NO | self. hidden = YES | self. alpha <= 0.01)
Return nil;
// 2. Determine whether the touch point is not in the current control
If (! [Self pointInside: point withEvent: event]) return nil;
// 3. traverse the child control from the back
Int count = (int) self. subviews. count;
For (int I = count-1; I> = 0; I --){
UIView * childV = self. subviews [I];
// Convert the points in the current coordinate system to the points in the subcontrol coordinate system.
CGPoint childP = [self convertPoint: point toView: childV];
// Determine whether your child control is the most suitable View
UIView * fitView = [childV hitTest: childP withEvent: event];
// If the child control is the best View, return directly
If (fitView ){
Return fitView;
}
}
// 4. You are the most suitable View
Return self.
I. Exercise 1
1. business logic: Add a button and a Blue view to the view.
There is a button at the bottom. There is a View on the top of the button, which is blocked on the button.
When you click View, View receives events. When you find that the clicked point is at the button position, let the button at the bottom process the events.
Details
2. Implementation ideas:
Implement the touchBegain method of the Blue View, first listen to the click of the UIView.
And implement the HitTest method of UIView. In the hitTest method, convert the current vertex to the coordinate system of the button.
CGPoint btnP = [self convertPoint: point toView: self. btn];
After conversion, check that the current point is not on the button. If it is on the button, return the button directly.
If it is not on the button, keep the system default practice.
3. Implementation code in the Blue view:
-(UIView *) hitTest :( CGPoint) point withEvent :( UIEvent *) event {
Judge whether the current point is not on the button.
Convert the current vertex to the coordinate system of the button
CGPoint btnP = [self convertPoint: point toView: self. btn];
If ([self. btn pointInside: btnP withEvent: event]) {
Return self. btn;
} Else {
Return [super hitTest: point withEvent: event];
}
}
Ii. Exercise 2
Business logic:
Add a button to the button. The added button is outside the parent control. You can drag the button with your finger. During the drag process, the Child control in the button is also dragged.
A child control that exceeds the button can also respond to events. Generally, when a control exceeds its parent control, it cannot receive events.
Now let the buttons that exceed the parent control be able to respond to events.
As follows:
Implementation ideas:
Step 1: First let the button move with the finger.
The touchesMoved method that implements the button. In the touchesMoved method, obtain the point where the current finger is located. Previous vertex.
Calculate the offset of the X axis and the offset of the Y axis respectively.
Then modify the transform of the current button so that the button can move with the finger.
Step 2: implement the hitTest method of the button.
In this method, the current point is determined not on the Child control of the button.
If the child control of the button is displayed, if the child control of the button is not displayed, the system will keep the default method.
Implementation Code:
ViewController. m file
# Import "ViewController. h "# import" chatBtn. h "@ interface ViewController () @ end @ implementation ViewController-(void) viewDidLoad {[super viewDidLoad];}-(IBAction) btnClick :( chatBtn *) sender {UIButton * btn = [UIButton buttonWithType: Custom]; [btn setImage: [UIImage imageNamed: @ "dialog box"] forState: Custom]; [btn setImage: [UIImage imageNamed: @ ""] forState: UIControlStateHighlighted]; sender. popBtn = btn; btn. frame = CGRectMake (100,-80,100, 80); [sender addSubview: btn];} @ end
ChatBtn. h file
# Import
@ Interface chatBtn: UIButton/** pop-up button */@ property (nonatomic, weak) UIButton * popBtn; @ end
ChatBtn. m file
# Import "chatBtn. h "@ implementation chatBtn-(UIView *) hitTest :( CGPoint) point withEvent :( UIEvent *) event {if (self. popBtn) {// return self. popBtn; // judge whether the current point is not on popBtn // convert the current point to CGPoint popBtnP on popBtn = [self convertPoint: point toView: self. popBtn]; if ([self. popBtn pointInside: popBtnP withEvent: event]) {return self. popBtn;} else {return [super hitTest: point withEvent: event] ;}} else {return [super hitTest: point withEvent: event] ;}}-(void) touchesMoved :( NSSet
*) Touches withEvent :( UIEvent *) event {// 1. obtain UITouch * touch = [touches anyObject]; // 2. obtain the point of the current finger. CGPoint curP = [touch locationInView: self]; CGPoint preP = [touch previuslocationinview: self]; // 3. calculates the offset CGFloat offsetX = curP. x-preP. x; CGFloat offsetY = curP. y-preP. y; // 4. translation self. transform = CGAffineTransformTranslate (self. transform, offsetX, offsetY);} @ end