perspective transform on uiview - iphone

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).

Related

How to change for 3D rotation on UIPanGesture?

I have done animation opening a page on tapping on it but now I have to change it for Pan Gesture. How should I start?
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
CALayer *layer = ges.view.layer;
CATransform3D initialTransform = ges.view.layer.transform;
initialTransform.m34 = 1.0 / -1100;
layer.transform = initialTransform;
layer.anchorPoint = CGPointMake(-0.0, 0.5);
[UIView beginAnimations:#"Scale" context:nil];
[UIView setAnimationDuration:2];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
CATransform3D rotationAndPerspectiveTransform = ges.view.layer.transform;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, -M_PI , 0 , -ges.view.bounds.size.height/2, 0);
ges.view.transform = CGAffineTransformRotate(ges.view.transform, 0);
layer.transform = rotationAndPerspectiveTransform;
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
UIPanGestureRecognizer myPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(imagePanned:)];
[_panGesture setMaximumNumberOfTouches:1];
[yourView addGestureRecognizer:myPanGesture];
1) if you want page to turn along with the pan action as user moves the view then you have to do this way.
- (void)imagePanned:(UIPanGestureRecognizer *)iRecognizer {
CGPoint translation = [recognizer translationInView:self.view];
//Calculate transformation based on the translation value of pan gesture, this will be a tricky part
[UIView animateWithDuration:0.5 delay: 0 options: 0 animations:
^(void) {
//Apply transformation
}
completion: nil];
}
Hope this will help you.
Edit : Extended Answer
*This goes with the first idea*
You just want to rotate the view right ?
then use CATransform3D, here you will need to calculate the iAngle that we are applying to view.
iAngle = //Calculate based on translation
where translation is
CGPoint translation = [recognizer translationInView:self.view];
Then apply transformation to view
CATransform3D myTransform = CATransform3DIdentity;
myTransform.m34 = 1.0 / -500;
myTransform = CATransform3DRotate(myTransform, DEGREES_TO_RADIANS(-iAngle), 0.0f, 1.0f, 0.0f); //#define DEGREES_TO_RADIANS(d) (d * M_PI / 180)
yourView.layer.transform = myTransform;
I'll give you the math behind doing it as I don't have code right now to show. Converting finger movement to rotation value is simply a matter of setting up ratios.
For angle value (used in transform):
track_spread rotation_angle
____________ = ______________
movement_x angle = ?
angle = (rotation_angle * movement_x)/track_spread;
WHERE:
track_spread = width_of_your_view (or less e.g. 70% x width_of_your_view)
rotation_angle = the final rotation you want for your view (a constant e.g. 45 degrees)
CGPoint point = [recognizer translationInView:self];
movement_x = abs(point.x);
angle = the value (in degrees) you are interested in and will input into transform after converting to radians
If someone cant figure out and still need code snippet please leave a comment.

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

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.

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.

CATransForm3D matrix issue

If you want to rotate an object using core animation, in radians, in the z axis, which of the following key paths of layer's CATransform3D matrix will you use? (more than 1 options can be right).
rotation
rotation.xy
rotation.x
rotation.y
rotation.z
Not totally clear about the options you gave, but I use the code below to do rotation:
[[_yourView layer] setAnchorPoint:CGPointMake(0.0f, 0.5)];
[UIView animateWithDuration:1.0f
delay:0.0f
options:UIViewAnimationCurveEaseInOut
animations:^{
CATransform3D rotation = CATransform3DIdentity;
rotation.m34 = 1.0f / -300.0f;
rotation = CATransform3DRotate(rotation, -60.0f * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
[[_yourView layer] setTransform:rotation];
}
completion:nil];
It is rotated in y axis(so, the view will change in z direction), you can set the rotation for other axis by setting the params below:
rotation = CATransform3DRotate(rotation, -60.0f * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
None of the above. Use transform.rotation.z