An example is given to illustrate how to write hitTest touch events in iOS application development

  • 2020-06-01 11:02:14
  • OfStack

hitTest: withEvet calls the procedure

So if you have the current View A, you have an viewB

If you do not override the hitTest method, the default is to call the hitest method of viewA and then the htest method of viewB.

The system's call process is 1-mode 1, as shown in the following method, which overrides hitest.


-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

    if ([self pointInside:point withEvent:event]) { 
    } 
    else { 
        return nil; 
    } 
    for (UIView *subView in self.subviews) { 
        if ([subView hitTest:point withEvent:event]!=nil) { 
            return subView; 
        } 
    } 
     
    return self; 


If you do not override the hitest method, the default hitest method for each UIVIeew will be the same as the above process.

There's nothing to say.

But for a particular process, that's not the case

So the reason for rewriting the hitTest method is usually to penetrate the upper UIview, so that the touch event can reach the lower uiview,

Like view A and VIew B,

View b completely blocks view A, but I want view A to respond to the event of the click when I click viewB. You can use the following methods:


-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event 

    if ([self pointInside:point withEvent:event]) { 
        NSLog(@"in view A"); 
        return self; 
    } 
    else { 
        return nil; 
    } 
 

in-depth
So let's go a little bit further 1, and now we have an example of the requirements interface as follows,

Window

- ViewA

- ButtonA

- ViewB

- ButtonB

Hierarchy: ViewB completely covers ButtonA, ButtonB on ViewB, now you need to implement:
(1) both ButtonA and ButtonB can respond to messages (2) ViewA can also receive touches messages received by ViewB (3) ViewB (ButtonB) cannot receive messages.

(first parse, by default, the ButtonB region, iOS message process, is clicked.

-ViewA

- ButtonA

- ViewB

- ButtonB

When the ButtonB area is clicked, the process: hitTest is called successively from ViewA

The values of pointInside are in order:

ViewA: NO;

ViewB: YES;

ButtonB: YES;

subViews: NO;

Therefore, ButtonB's subViews's hitTest all return nil, so the returned processing object is ButtonB itself. The next step is to start working with the touches family of methods, which is the method that calls the ButtonB binding. After processing, the message stops and the whole process ends.

Analysis:

There are many ways to do this, but the two requirements are implemented separately, because implementation 2 satisfies 1.

For the implementation of requirement 1, ViewB covers ButtonA, so ButtonA will not receive messages by default. However, the search for message response in the message mechanism starts from the parent View, so we can judge in ViewA's hitTest method. If touch point is on ButtonA, ButtonA will be returned as the message processing object.

The code is as follows:


#pragma mark - hitTest
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // when touch point Is in the _btn , hitTest return _btn
    CGPoint btnPointInA = [_btn convertPoint:point fromView:self];
    if ([_btn pointInside:btnPointInA withEvent:event]) {
        return _btn;
    }
    
    // Otherwise, return the default processing
    return [super hitTest:point withEvent:event];
    
}

Thus, when the touch point is on ButtonA, the touch message is intercepted on ViewA, and ViewB cannot receive it. Then ButtonA receives an touch message, which triggers the onClick method.

Implementation of requirement 2, as mentioned above in response chain, ViewB only needs to override to drop the touches series method, and then pass the message to the next responder (i.e., parent View or ViewA) after processing it itself.

The code is as follows: in the ViewB code


#pragma mark - touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"B - touchesBeagan..");
    
    // Pass the event on to the father View Or including his ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];
}
 
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"B - touchesCancelled..");
    // Pass the event on to the father View Or including his ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];
}
 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"B - touchesEnded..");
    // Pass the event on to the father View Or including his ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];
}
 
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"B - touchesMoved..");
    // Pass the event on to the father View Or including his ViewController
    [self.nextResponder touchesBegan:touches withEvent:event];
    
}

Then, you can receive an touches message on ViewA, and write on ViewA:

#pragma mark - touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"A - touchesBeagan..");
}
 
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"A - touchesCancelled..");
}
 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"A - touchesEnded..");
}
 
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"A - touchesMoved..");
    
}

This makes it possible to send a message to the parent View.

If ViewB is not allowed to receive messages, ViewB. UserInteractionEnable=NO; In addition to this, override can also be ponitInside ViewB ponitInside, the principle of reference above.

Write on ViewB:


- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    // this View Does not respond to user events
    return NO;
 
}


Related articles: