Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does one have to use CALayer's presentationLayer for hit-testing?

I was working on a Cocoa Touch application, and trying to handle touches by determining which sublayer of a view's layer was touched. My controller's code looked like this:

CALayer *hitLayer = [self.view.layer hitTest:point];

This wasn't working. It would work if I tapped at the bottoms of sublayers, but not at the tops. After an hour of hair-pulling and Googling, I finally figured out that it works if one uses the presentation layer to do the hit-testing instead of the layer itself:

CALayer *hitLayer = [self.view.layer.presentationLayer hitTest:point];

So, I've solved my problem, but my question is: Why?

I've read through the Core Animation guide, and I understand that the presentation tree and rendering tree can differ from the object-model tree. But I don't understand why the presentation tree would (apparently) have different hit-testing behavior. Wouldn't the presentation tree and object-model have the same frames, bounds, etc.?

like image 911
Kristopher Johnson Avatar asked Feb 04 '10 11:02

Kristopher Johnson


2 Answers

According to the CALayer documentation, there seems to be a difference between the model and the presentation tree regarding what is presented to the user (depending on the ongoing animation). For hit testing, there is a reference in the presentationLayer method:

For example, sending a hitTest: message to the presentationLayer will query the presentation values of the layer tree.

So I suspect that only presentation layer has the right geometry information to perform the hit test.

like image 93
Laurent Etiemble Avatar answered Nov 14 '22 00:11

Laurent Etiemble


Kristopher, I had a very similar issue too. However, when I converted the point to the super layer or super views coordinate system it worked perfectly. I did not use the presentation layer.

    //Identify the touch point in the view. Using UITapRecognizer
CGPoint loc = [recognizer locationInView:recognizer.view];

//convert the point to superview co-ordinates and then identify the layer using hit test.
CALayer *layer = [self.layer hitTest:[self convertPoint:loc toView:self.superview]];

This returns me the layer that was touched, at least for now. Let us know if you think this is a wrong approach and I should be using presentation-layer instead.

like image 31
Murali Raghuram Avatar answered Nov 14 '22 01:11

Murali Raghuram