how to rotate a view from left to right using CATransform3DMakeRotation - iphone

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);
}

Related

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.

perspective transform on uiview

Here's the basic code to get started with:
[UIView transitionWithView:self.view duration:2.0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^ {
CALayer *layer1 = leftband.layer;
layer1.anchorPoint = CGPointMake(0, 0.5);
CATransform3D rotationAndPerspectiveTransform1 = CATransform3DIdentity;
rotationAndPerspectiveTransform1.m34 = 1.0 / -500;
rotationAndPerspectiveTransform1 = CATransform3DRotate(rotationAndPerspectiveTransform1, DegreesToRadians(-180.0f), 0.0f, 1.0f, 0.0f);
layer1.transform = rotationAndPerspectiveTransform1;
CALayer *layer2 = rightband.layer;
layer2.anchorPoint = CGPointMake(0, 0.5);
CATransform3D rotationAndPerspectiveTransform2 = CATransform3DIdentity;
rotationAndPerspectiveTransform2.m34 = 1.0 / -500;
rotationAndPerspectiveTransform2 = CATransform3DRotate(rotationAndPerspectiveTransform2, DegreesToRadians(180.0f), 0.0f, 1.0f, 0.0f);
layer2.transform = rotationAndPerspectiveTransform2;
}
completion:nil {
}];
leftband and rightband are two UIImageViews. The effect I want is that the leftband animates with its transform along the Y-axis towards the left direction. And the rightband does the same along its Y-axis towards the right.
But the above code results in both left and right imageviews animating in the same direction (it happens only towards left). I guess my understanding of anchor points is wrong. Both -180° and +180° in the rotation transform result in a leftward animation.
What am I doing wrong here?
Basically setting the anchor points before the animation block runs solves the issue. Anchor point for left -> (0.0f,0.5f) and for right -> (1.0f,0.5f).

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.

Why CABasicAnimation will send the layer's view to back and front?

There are two UIViews of similar size. UIView one (A) is originally on top of UIView two (B). When I try to perform a CABasicAnimation transform.rotation.y on A's layer:
CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
CGFloat startValue = 0.0;
CGFloat endValue = M_PI;
rotateAnimation.fromValue = [NSNumber numberWithDouble:startValue];
rotateAnimation.toValue = [NSNumber numberWithDouble:endValue];
rotateAnimation.duration = 5.0;
[CATransaction begin];
[imageA.layer addAnimation:rotateAnimation forKey:#"rotate"];
[CATransaction commit];
During the animation, the animating layer's UIView (A) will be:
sent back (A is suddenly behind B)
rotating ... passed second half of the animation
sent front (A is now on top of B again)
Is there a way to keep A on top of B for the whole animation period? Thanks!
UPDATE: project source is attached: FlipLayer.zip
The problem is a rotation around the Y axis will, in a true 3D compositing system, make layer A intersect with layer B, such that half of layer A should be visible and half should be behind layer B. CoreAnimation does not provide a true 3D compositing system. Instead it attempts to determine which layer is in front of which other layer, and renders it entirely without intersection. In your case, during the first half of the rotation CoreAnimation has decided that layer B is on top of layer A in the 3D space. The simplest solution is probably to set the zPosition of layer A to layer.bounds.size.width (default is 0) for the duration of the animation (or permanently, if it should always be on top).
If you want to set it only for the duration of the animation, you can add a second animation for the transform.translation.z key path. Here's your -flip method modified to use this:
- (IBAction)flip:(id)sender {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
CGFloat startValue = 0.0;
CGFloat endValue = M_PI;
animation.fromValue = [NSNumber numberWithDouble:startValue];
animation.toValue = [NSNumber numberWithDouble:endValue];
animation.duration = 5.0;
[imageOne.layer addAnimation:animation forKey:#"rotate"];
animation.keyPath = #"transform.translation.z";
animation.fromValue = [NSNumber numberWithFloat:imageOne.layer.bounds.size.width];
animation.toValue = animation.fromValue;
[imageOne.layer addAnimation:animation forKey:#"zPosition"];
}
Have you tried adding a [self.view bringSubviewToFront:imageA]; in your animation sequence?
You could try to translate on the z axis and bring A forward first. Perform the rotation and then set the z back to its starting value.
Also, you probably won't see any perspective on the rotation unless you set the .m34 property on the transform. Try something like this:
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0f / -300.0f;
transform = CATransform3DRotate(transform, 0.0f, M_PI, 0.0f);
CABasicAnimation *rotateAnimation = [CABasicAnimation
animationWithKeyPath:#"transform"];
rotateAnimation.fromValue = [NSValue
valueWithCATransform3D(CATransformIdentity)];
rotateAnimation.toValue = [NSValue valueWithCATransform3D(transform)];
rotateAnimation.duration = 5.0;
[imageA.layer addAnimation:rotateAnimation forKey:#"rotate"];
You transaction block is unnecessary.
Best Regards.