The Secret Life of a CALayer (Part 2): Sublayers and hitTests (Xcode)


A UIView can have any number of subviews and we add them like this:

UIView *yourSubview = [[UIView alloc] init];

[yourView addSubview:yourSubview];

Likewise a CALayer can have any number of sublayers.
UIView *yourSublayer = [[UIView alloc] init];
[yourView.layer addSublayer:yourSublayer];

But because a CALayer, unlike UIView, UIViewController, UIImageView, UISlider, UIApplication and UIWindow, does not inherit from UIResponder and does not handle touch events, we use the hitTest: method to discover which layer has been touched.

In this example there are four layers, so let's place this information in the interface of our view controller .m file:
@interface HitTestViewController ()

{

    CALayer *blueLayer;
    CALayer *redLayer;
    CALayer *yellowLayer;
    CALayer *greenLayer;

}

@end

Next we're going to create the layers and add them to our self.view.layer giving each one a name as we go:
-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    blueLayer = [[CALayer alloc] init];
    blueLayer.frame = CGRectMake(100, 100, 100, 100);
    blueLayer.backgroundColor = [UIColor blueColor].CGColor;
    blueLayer.name = @"Blue";
    [self.view.layer addSublayer:blueLayer];
    
    redLayer = [[CALayer alloc] init];
    redLayer.frame = CGRectMake(200, 200, 100, 100);
    redLayer.backgroundColor = [UIColor redColor].CGColor;
    redLayer.name=@"Red";
    [self.view.layer addSublayer:redLayer];
    
    yellowLayer = [[CALayer alloc] init];
    yellowLayer.frame = CGRectMake(300, 300, 100, 100);
    yellowLayer.backgroundColor = [UIColor yellowColor].CGColor;
    yellowLayer.name = @"Yellow";
    [self.view.layer addSublayer:yellowLayer];
    
    greenLayer = [[CALayer alloc] init];
    greenLayer.frame = CGRectMake(400, 400, 100, 100);
    greenLayer.backgroundColor = [UIColor greenColor].CGColor;
    greenLayer.name=@"Green";
    [self.view.layer addSublayer:greenLayer];
    
    
}
The next step is to use the UIViewController's inheritance from the UIResponder class to take advantage of the touchesEnded: method.
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
    CGPoint location = [[touches anyObject] locationInView:self.view];
    CALayer *hitLayer = [self.view.layer hitTest:[self.view convertPoint:location fromView:nil]];
    
    
   [self displayInfo:hitLayer.name];
}
The first two lines of code are borrowed almost verbatim from Apple's documentation, which can be found here. The remaining line is self explanatory once we add the displayInfo: method. Like so:
-(void)displayInfo:(NSString *)nameOfLayer
{
    NSLog(@"%@",nameOfLayer);
}
Now all that remains is to run, tap the layers, and see what comes up in the console. If you've errors then likely you forgot to add the QuartzCore framework and the instruction to import it. Return to the earlier post to learn how you do this.

The Secret Life of a CALayer: Part 1 | Part 2 Part 3 | Part 4


Comments