views:

3611

answers:

7

There are methods to transfer a CGPoint from one UIView to another and from one CALayer to another. I cannot find a way to change a CGPoint from a UIView's coordinate system to a CALayer's coordinate system.

Does a layer and it's host view have the same coordinate system? Do I need to transform points between them?

Thanks, Corey

A: 

I believe the two have the same coordinate system.

Ben Alpert
A: 

I believe the coordinate system of a UIView and its associated layer should be the same. However, if you create layers yourself, the coordinate system is flipped vertically.

Kevin Ballard
+1  A: 

You can set the transform property of CALayers to the appropriate transform if you want to flip their coordinate system, but note that this will probably flip their drawing of the contents as well (I have not tested that, but it makes sense that this would be true). My assertion that the CALayer associated with a UIView shares the same coordinate system could in fact be entirely erroneous. It could also be that CALayers use the same coordinate system as UIViews (i.e. they're never flipped vertically), but I thought they were since CoreGraphics uses a flipped coordinate system relative to UIKit.

A simple way to test would be to add a screen-sized CALayer as the sublayer of a view's layer, then add another small CALayer as a sublayer of that. You could set it to show up at (0, 0, 320, 100) and see if it shows up on the top or the bottom of the iPhone's screen. This will tell you in which direction the Y axis goes for CoreAnimation.

- (void)viewDidLoad {
  [super viewDidLoad];
  CALayer *rootLayer = [CALayer layer];
  rootLayer.frame = self.view.layer.bounds;
  CALayer *smallLayer = [CALayer layer];
  smallLayer.frame = CGRectMake(0, 0, rootLayer.bounds.size.width, 50);
  smallLayer.backgroundColor = [UIColor blueColor].CGColor;
  [rootLayer addSublayer:smallLayer];
  [self.view.layer addSublayer:rootLayer];
}

I just performed this test myself, and it appears CALayers actually use the same coordinate system as UIViews, so my assertion that CALayer's flip the Y axis is definitely wrong. However, if you do drawing with CoreGraphics directly, be aware that CoreGraphics does use a flipped Y axis (though when drawing in a UIView subclass or, I assume, a CALayer delegate, the CoreGraphics context has already been flipped to match the UIView's (or CALayer's) coordinate system).

So the short answer, if you made it this far, is the coordinate system for CALayer should match the coordinate system for its corresponding UIView.

Kevin Ballard
Kevin, if you have the time would you mind looking at my main thread listed in my post below. You seem to be pretty knowledgeable in this are and any insights are appreciated. Thanks again
Corey Floyd
A: 

Thanks for the answer! It is hard to find information on the differences/similarities between CA on the iPhone and Mac. I am surprised I couldn't find this issue addressed directly in any Apple Documentation.

I was pursuing this answer to help with a bug I am troubleshooting, and this was so far my best guess, but I suppose I am barking up the wrong tree. If the coordinate systems are the same, then I have another issue...

The actual issue I am having can be found here on Stack Overflow: layer hit test only returning layer when bottom half of layer is touched

Corey Floyd
+4  A: 

The documentation for hitTest says:

/* Returns the farthest descendant of the layer containing point 'p'.
 * Siblings are searched in top-to-bottom order. 'p' is in the
 * coordinate system of the receiver's superlayer. */

So you need to do (something like this):

CGPoint thePoint = [touch locationInView:self];
thePoint = [self.layer convertPoint:thePoint toLayer:self.layer.superlayer];
CALayer *theLayer = [self.layer hitTest:thePoint];
schwa
A: 

From my tests I've found out that sublayers share the same coordinate system as it's parent layer and therefore if you are adding sublayer to a UIView layer then they will share the same coordinate system.

In case you still want to flip the coordinate system so that it's origin is in the upper left corner you should use this transformation that flips the y axis. (x,y,1) = (x', y', 1) * [1 0 0],[0 -1 0],[0 heigth 1]

which translated to code is: [your_layer setAffineTransform:CGAffineTransformMake(1,0,0,-1,0,heigth)];

Marc M
+2  A: 

In terms of Apple documentation, I found an "iPhone OS Note" in the Layer Coordinate System section of the Core Animation Programming Guide (2008-11-13).

The default root layer of a UIView instance uses a flipped coordinate system that matches the default coordinate system of a UIView instance–the origin is in the top-left and values increase down and to the right. Layers created by instantiating CALayer directly use the standard Core Animation coordinate system.

otto