Question

I'm trying to detect touches in my view.app screenshot

My code:

- (CALayer *)layerForTouch:(UITouch *)touch {
    UIView *view = self;

    CGPoint location = [touch locationInView:view];
    location = [view convertPoint:location toView:nil];

    CALayer *hitPresentationLayer = [view.layer.presentationLayer hitTest:location];
    if (hitPresentationLayer) {
        return hitPresentationLayer.modelLayer;
    }

    return nil;
}

But I found problem. It's detecting just first layer in tree.

Every figure on screenshot - one layer. I'm drawing it's from the biggest to the smallest as tree.

Was it helpful?

Solution

if your topmost layer covers the whole screen (or other below layers) then yes you will get the top most layer during hitTest check. you can do a containsPoint check for all your layers if you want to check it further below. Do find some sample code below

   @interface ViewController ()

@property (nonatomic, strong) CALayer *layer1;
@property (nonatomic, strong) CALayer *layer2;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    CALayer *layer = [[CALayer alloc] init];
    layer.frame = (CGRect) { 10, 10, 100, 100 };
    [self.view.layer addSublayer:layer];
    layer.backgroundColor = [UIColor redColor].CGColor;
    self.layer1 = layer;

    layer = [[CALayer alloc] init];
    layer.frame = (CGRect) { 60, 60, 100, 100 };
    [self.view.layer addSublayer:layer];
    layer.backgroundColor = [UIColor blueColor].CGColor;
    self.layer2 = layer;

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint touchPoint = [(UITouch*)[touches anyObject] locationInView:self.view];
    CALayer *touchedLayer = [self.view.layer.presentationLayer hitTest:touchPoint];

    CALayer *originalLayer = [touchedLayer modelLayer];

    if (originalLayer == self.layer1) { NSLog(@"layer 1 touched"); }

    if (originalLayer == self.layer2) { NSLog(@"layer 2 touched"); }

    for ( CALayer *layer in @[self.layer1, self.layer2])
    {
        CGPoint point = [layer convertPoint:touchPoint fromLayer:self.view.layer];
        NSLog(@"layer %@ containsPoint ? %@",layer, [layer containsPoint:point]? @"YES":@"NO");
        NSLog(@"original point : %@ | converted point : %@",NSStringFromCGPoint(touchPoint),NSStringFromCGPoint(point));
    }
}

@end

Or you can try using CAShapeLayers & match with the CGPath of ShapeLayer to see if its touched like the example below ..

@interface ViewController ()

@property (nonatomic, strong) CALayer *layer1;
@property (nonatomic, strong) CALayer *layer2;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.path = [UIBezierPath bezierPathWithRect:(CGRect){ 0,0,100,10 }].CGPath;
    shapeLayer.backgroundColor = [UIColor redColor].CGColor;
    shapeLayer.frame = (CGRect){20, 20, 100, 100};
    [self.view.layer addSublayer:shapeLayer];
    self.layer1 = shapeLayer;

    shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.path = [UIBezierPath bezierPathWithRect:(CGRect){ 0,0,10,100 }].CGPath;
    shapeLayer.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:0.6].CGColor;
    shapeLayer.frame = (CGRect){60, 60, 100, 100};
    [self.view.layer addSublayer:shapeLayer];
    self.layer2 = shapeLayer;

}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint touchPoint = [(UITouch*)[touches anyObject] locationInView:self.view];
    CALayer *touchedLayer = [self.view.layer.presentationLayer hitTest:touchPoint];

    CALayer *originalLayer = [touchedLayer modelLayer];

    for ( CAShapeLayer *layer in @[self.layer1, self.layer2])
    {
        if (![layer isKindOfClass:[CAShapeLayer class]]) { continue; }

        CGPoint point = [layer convertPoint:touchPoint fromLayer:self.view.layer];

        if (CGPathContainsPoint(layer.path, 0, point, 0))
        {
            NSLog(@"match found");

            if (originalLayer == self.layer1) { NSLog(@"layer 1 touched"); }
            if (originalLayer == self.layer2) { NSLog(@"layer 2 touched"); }
            return;
        }

    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top