I have an image in a CALayer (using the CALayers contents property). A CALayer has a transform property that can be use to scale and rotate. I can use that transform without difficulty when the CALayer is still.
But when I try to drag the CALayer (using mouseDragged:(NSEvent *)theEvent), then it all fells apart (the image gets flattened out as I drag).
-(void)mouseDragged:(NSEvent *)theEvent {
CGPoint loc = [self convertPoint:theEvent.locationInWindow fromView:nil];
CGPoint deltaLoc = ccpSub(loc, downLoc); // subtract two points
CGPoint newPos = ccpAdd(startPos, deltaLoc); // adds two points
[layer changePosition:newPos];
...
}
In the layer
-(void)changePosition:(CGPoint)newPos {
//prevent unintended animation actions
self.actions = @{@"position": [NSNull null]};
CGSize size = self.frame.size;
CGRect newRect = CGRectMake(newPos.x, newPos.y, size.width, size.height);
self.frame = newRect;
}
The problem is that I use CALayer's frame to dynamically change the location of the CALayer as I drag, but when the rotation angle is not zero, then the frame is not longer parallel to x and y axis. What is the best way to fix this problem?
One way to do it is to regenerate transforms for each incremental movement.
-(void)mouseDragged:(CGPoint)deltaLoc start:(CGPoint)startPos {
CGPoint newPos = ccpAdd(startPos, deltaLoc);
[self changePosition:newPos];
}
-(void)changePosition:(CGPoint)newPos {
//prevent unintended animation actions
self.actions = @{@"position": [NSNull null]};
double angle = [[self valueForKeyPath: @"transform.rotation"] doubleValue];
double scaleX = [[self valueForKeyPath: @"transform.scale.x"] doubleValue];
double scaleY = [[self valueForKeyPath: @"transform.scale.y"] doubleValue];
self.transform = CATransform3DIdentity;
CGSize size = self.frame.size;
CGRect newRect = CGRectMake(newPos.x, newPos.y, size.width, size.height);
self.frame = newRect;
[self applyTransformRotation:angle scale:ccp(scaleX, scaleY)];
}
-(void)applyTransformRotation:(double)angle scale:(CGPoint)scale {
self.transform = CATransform3DMakeRotation(angle, 0, 0, 1);
self.transform = CATransform3DScale(self.transform, scale.x, scale.y, 1);
}
I do not know if this is the most efficient way to do it, but it definitely works.