How can I add an image to the back of a CALayer after rotate 90 degrees? - iphone

I want to add a back image to a CALayer when the my rotation transform degree is higher than 90.
It is just like a Flipboard flip animation.
This is my current code:
CALayer *layer = self.view.layer;
int frames = 130;
layer.anchorPoint = CGPointMake(0, 0.5);
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / -2000.0;
transform = CATransform3DRotate(transform, -frames * M_PI / 180.0, 0.0, 1.0, 0.0);
self.view.layer.transform = transform;
CAKeyframeAnimation *pivot = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
NSMutableArray *values = [[NSMutableArray alloc] initWithCapacity:45];
NSMutableArray *times = [[NSMutableArray alloc] initWithCapacity:45];
for (int i = 0; i < frames; i++) {
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / -2000.0;
transform = CATransform3DRotate(transform, -M_PI / 180.0 * i, 0.0, 1.0, 0.0);
[values addObject:[NSValue valueWithCATransform3D:transform]];
[times addObject:[NSNumber numberWithFloat:(float)i / (frames - 1)]];
}
pivot.values = values;
pivot.keyTimes = times;
[values release];
[times release];
pivot.duration = 0.5f;
pivot.calculationMode = kCAAnimationLinear;
[layer addAnimation: pivot forKey: #"pivot"];
Could anyone tell me how to add a back image just like the flip effect.

As far as I know, the easiest way to do it is to add two sublayers representing the front side and the back side of the page. Set both the sublayers' doubleSided property to NO. Set the back side layer transform to the same flipped transform you're animating to. Then, when the page's front side faces the viewer, the front side layer is visible and the back side layer is "hidden", and vice versa.
See GeekGameBoard source code (Card.m) for a sample of the technique.

Related

how to rotate a view from left to right using CATransform3DMakeRotation

I know how to rotate a view from right to left
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DMakeRotation(M_PI, 0.0f, 1.0f, 0.0f);
transform.m34 = 0.0015;
view.layer.transform = transform;
But i cant rotate it from left to right.
Please help me.
I'm not sure what you mean by “left to right” and “right to left”. Anyway, as you have discovered, you can't control the direction of the animation just by setting the transform matrix, because both -M_PI and +M_PI have the same final effect, so there's no way for Core Animation to reliably know which way you want it to rotate.
Instead, you can animate the transform.rotation.y key path of the layer. This is a little more complicated to do, particularly since you want to animate a view's layer instead of a freestanding layer (not controlled by a view).
Anyway, here's the code I tested:
- (IBAction)rotateButtonWasTapped:(id)sender {
// Establish the perspective to be used during the animation.
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 0.0015;
self.imageView.layer.transform = transform;
static CGFloat kAngle = -M_PI;
[CATransaction begin]; {
// After the animation completes, make the transform “permanent”. Otherwise it
// will be undone when the animation is removed from the layer.
[CATransaction setCompletionBlock:^{
self.imageView.layer.transform = CATransform3DRotate(transform, kAngle, 0, 1, 0);
}];
// Animate the rotation using Core Animation's extension to Key Value Coding.
// The sign of kAngle determines the direction of rotation.
CABasicAnimation *animation = [CABasicAnimation
animationWithKeyPath:#"transform.rotation.y"];
animation.fromValue = #0;
animation.toValue = #(kAngle);
animation.duration = 1;
[self.imageView.layer addAnimation:animation forKey:animation.keyPath];
} [CATransaction commit];
}
This rotates the view such that the left edge of the view moves “closer” to the user during the rotation. If that's not what you mean by “left to right”, change the definition of kAngle to M_PI and it will rotate in the other direction. I have tested both ways. You can even spin the layer multiple times in one animation. For example, try defining kAngle as -3 * M_PI.
I did not find anything in the function documentation, but I think you can just make the rotation angle negative to rotate into the other direction.
if you want to rotate the view, back to the initial position... just do it with:
transform = CATransform3DMakeRotation(0, 0.0f, 1.0f, 0.0f)
or you can "combine" more..
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DMakeRotation(-M_PI_2, 0.0f, 1.0f, 0.0f);
transform = CATransform3DMakeRotation(0, 0.0f, 1.0f, 0.0f);
transform.m34 = 0.0015;
view.layer.transform = transform;
You can try... to use CATransform3D transform = starLayer.transform; instead of CATransform3D transform = CATransform3DIdentity;
-(void)updateTimer
{
if(update<125)
update=update+1;
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval interval = now - start;
int inter = (int)(interval*update);
inter*=10;
milliSec = (inter) % 1000;
seconds = (inter/1000) % 60;
minutes = (inter/60000) % 60;
timeValue = oldTimeValue+inter;
// Set Digital clock
// Set Analog clock hands
secHand.layer.transform = CATransform3DMakeRotation (Degrees2Radians(-(timeValue%1000)*360/1000), 0, 0, 1);
}

How to make image rotation and 3D transform simultaneously?

I am working on image editing application(resize, rotation, 3d transform). If I am rotate the image and then make 3D transform. Its going to initial image. Otherwise I am change the 3D transform then make rotation, Its also goes to the initial state.
For image 3D Transform I am using below code :
- (void)moveImage:(UIPanGestureRecognizer *)recognizer
{
if ([recognizer respondsToSelector:#selector(translationInView:)]) {
CGPoint translation = [(UIPanGestureRecognizer *)recognizer translationInView:recognizer.view.superview];
CALayer *layer = self.layer;
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / 500.0;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, - self.xTranslation / 50.0 * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
layer.transform = rotationAndPerspectiveTransform;
rotationAndPerspectiveTransform.m34 = - 1.0 / 500.0;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, - self.yTranslation / 50.0 * M_PI / 180.0f, 1.0f, 0.0f, 0.0f);
layer.transform = rotationAndPerspectiveTransform;
}
}
For image Rotation I am using below code :
- (void)rotateImage:(UIRotationGestureRecognizer *)recognizer
{
if (state == RSImageViewStateResizing) {
recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
recognizer.rotation = 0;
}
}
How to I fix this issue. Always welcome your suggestions, sample code, Sample project, any App store applications. Thanks in advance. Any one help me.
Use CAAnimationGroup to combine multiple animation into one
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.animations=[NSArray arrayWithObject:resizeAnimation, rotationAnimation, 3d transformAnimation];// add here your CAAnimation reference and CATransform3D reference
[layer addAnimation:theGroup forKey:#"animatePosition"];

Rotate a UIImageView around a point off screen? (center of uiImageView

Hi I have a UIImageView which is part on, part off screen.
I want to rotate the view around a point off screen (the center of the view.)
How do I do this?
fullRotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotationAnimation.fromValue= [NSNumber numberWithFloat:0.0f];
fullRotationAnimation.toValue = [NSNumber numberWithFloat:2 * M_PI];
fullRotationAnimation.duration = 4;
fullRotationAnimation.repeatCount = 1;
[self->greyRings.layer addAnimation:fullRotationAnimation forKey:#"360"];
I'm using that code at the moment but it just spins it around the center of the screen.
Any ideas please?
Using block animation:
- (void)rotateImageView:(UIImageView *)imageView aroundPoint:(CGPoint)point byAngle:(CGFloat)angle {
CGFloat sinA = sin(angle);
CGFloat cosA = cos(angle);
CGFloat x = point.x;
CGFloat y = point.y;
CGAffineTransform transform = CGAffineTransformMake(cosA,sinA,-sinA,cosA,x-x*cosA+y*sinA,y-x*sinA-y*cosA);
[UIView animateWithDuration:4.0 animations:^{
imageView.transform = transform;
}];
}
Note that angle is in radians, so a full rotation is 2.0*M_PI.
Maybe you have to set anchorPoint of CALayer: see Specifying a Layer’s Geometry for more detail.
//(0,0) is the left-bottom of your layer bounds
self->greyRings.layer.anchorPoint = CGPointMake(0.0f, 0.0f);
I think a negative anchorPoint should also work. So you'd better give your bounds and we can calculate for you.

having trouble creating ken burns effect with CALayer for iphone

I have been trying for the last few days to create the ken burns effect using a CALayer with animations and then save it to a video file.
I have my image layer which is inside another layer that is 1024x576. All of the animations are applied to the image layer.
Here is the code so far:
- (CALayer*)buildKenBurnsLayerWithImage:(UIImage *)image startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint fromScale:(float)fromScale toScale:(float)toScale
{
float calFromScale = fromScale + 1;
float calToScale = toScale + 1;
float fromX = startPoint.x * calFromScale;
float fromY = (image.size.height * calFromScale) - (videoSize.height + (startPoint.y * calFromScale));
float toX = endPoint.x * calToScale;
float toY = (image.size.height * calToScale) - (videoSize.height + (endPoint.y * calToScale));
CGPoint anchor = CGPointMake(0.0, 0.0);
CALayer* imageLayer = [CALayer layer];
imageLayer.contents = (id)image.CGImage;
imageLayer.anchorPoint = anchor;
imageLayer.bounds = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
imageLayer.position = CGPointMake(image.size.width * anchor.x, image.size.height * anchor.y);
imageLayer.contentsGravity = kCAGravityResizeAspect;
// create the panning animation.
CABasicAnimation* panningAnimation = [CABasicAnimation animationWithKeyPath:#"position"];
panningAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(-fromX, -fromY)];
panningAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-toX, -toY)];
panningAnimation.additive = YES;
panningAnimation.removedOnCompletion = NO;
// create the scale animation.
CABasicAnimation* scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.fromValue = [NSNumber numberWithFloat:fromScale];
scaleAnimation.toValue = [NSNumber numberWithFloat:toScale];
scaleAnimation.additive = YES;
scaleAnimation.removedOnCompletion = NO;
CAAnimationGroup* animationGroup = [CAAnimationGroup animation];
animationGroup.animations = [[NSMutableArray alloc] initWithObjects:panningAnimation,scaleAnimation, nil];
animationGroup.beginTime = 1e-100;
animationGroup.duration = 5.0;
animationGroup.removedOnCompletion = NO;
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[imageLayer addAnimation:animationGroup forKey:nil];
return imageLayer;
}
Here is how i'm calling the method:
CALayer* animatedLayer = [self buildKenBurnsLayerWithImage:image startPoint:CGPointMake(100, 100) endPoint:CGPointMake(500, 500) fromScale:5.0 toScale:2.0];
The problem I am having is that the end result with panning and scaling is off by a few pixels on the screen.
If someone knows how to fix this i would great appreciate it.
All transformations are applied with respect to the anchor point. Try using the anchor point
CGPoint anchor = CGPointMake(0.5f, 0.5f);
Your "viewport" should no longer scale to the bottom right (if that is responsible for the animation being off by a few pixels), but equally to all directions.

Sequential UIView Transform

I've got a question about applying multiple transforms to an UIView. When I animate a rotation of an UIView around it's center point, for example, and then try to rotate it around a point that lies outside it's bounds after that, the second animation is all messed up, e.g. it jitters around or rotates in a completely different way than specified. How can I make it so that the first animation doesn't influence the second, but is still present when the second one is played?
EDIT: Here's the code. First I rotate the view around it's center point:
CALayer *layer = view.layer;
CATransform3D aTransform = CATransform3DIdentity;
CGFloat zDistance = 2000;
aTransform.m34 = 1.0 / -zDistance;
scrollView.layer.sublayerTransform = aTransform;
CGFloat subviewX = 0.5;
CGFloat subviewY = 0.5;
[self setAnchorPoint:CGPointMake(subviewX, subviewY) forView:view];
CATransform3D bTransform = CATransform3DIdentity;
CABasicAnimation *rotateAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
rotateAnim.fromValue= [NSValue valueWithCATransform3D:bTransform];
bTransform = CATransform3DRotate(aTransform,-20*M_PI/180, 1, 1, 0);
rotateAnim.duration=0.05;
rotateAnim.toValue=[NSValue valueWithCATransform3D:bTransform];
layer.transform = bTransform;
[layer addAnimation:rotateAnim forKey:nil];
Now that the layer is rotated, I want to flip it around the left screen border:
CALayer *layer = view.layer;
CATransform3D aTransform = CATransform3DIdentity;
CGFloat zDistance = 2000;
aTransform.m34 = 1.0 / -zDistance;
tileScrollView.layer.sublayerTransform = aTransform;
CGFloat subviewX = ((1/view.frame.size.width)*(view.frame.origin.x));
CGFloat subviewY = 0.5;
[self setAnchorPoint:CGPointMake(-subviewX, subviewY) forView:view];
CATransform3D bTransform = layer.transform;
CABasicAnimation *rotateAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
rotateAnim.fromValue= [NSValue valueWithCATransform3D:bTransform];
bTransform = CATransform3DMakeRotation(-M_PI_2, 0, 1, 0);
rotateAnim.duration=0.2;
rotateAnim.toValue=[NSValue valueWithCATransform3D:bTransform];
layer.transform = bTransform;
[layer addAnimation:rotateAnim forKey:nil];
Since I want the rotated layer to be flipped around, I put CATransform3D bTransform = layer.transform instead of CATransform3D bTransform = CATransform3DIdentity at the beginning of the second animation, but again, that only messes the animation up
Another, similar problem I have is that I have an UIView that contains 9 subViews, one of which flips around it's center point every second. But every time I apply a transformation to the superView of those 9 UIViews, the layout of the subViews gets messed up. Does anyone know how to prevent this? Any help would be greatly appreciated. Thanks in advance!
Two things:
In the first transform, you do this:
bTransform = CATransform3DRotate(aTransform,-20*M_PI/180, 1, 1, 0);
meaning that you rotate around an axis that is 45° between the x and y axis. That might be what you're trying to do, but it seems strange. Consider changing to
bTransform = CATransform3DRotate(aTransform,-20*M_PI/180, 0, 1, 0);
In the second step, if you just want to add the transform onto the current transform (i.e. rotate another 180°), you need to change this line
bTransform = CATransform3DMakeRotation(-M_PI_2, 0, 1, 0);
to
bTransform = CATransform3DRotate(bTransform, -M_PI_2, 0, 1, 0);
This applies the transformation to the existing transform, instead of ignoring the current transform.