How to make CATransform3dMakeRotation rotate the other way? And combine

I am working with Core Core Animation for the first time and in the process of implementing a game card that I can turn over, I decided to use CALayer to display the content (not sure how I "I'm going to get two sides, but that's another question), and I need be able to flip it, move it, etc.

I use CATransaction with some success - in the fragment below, the map moves from the lower left to the upper left corner and flips. The problem is that I don’t want to turn it over, but I don’t know how to say it: "hey, you are going wrong!"


 [CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration]; myCard.position = CGPointMake(CGRectGetMidX(self.bounds)/2,CGRectGetMidY(self.bounds)/2); myCard.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0); [CATransaction commit]; 

Second question: how can I get it to do two conversions at the same time? I tried to CATransactions two CATransactions , but the second only overrides the first. I also tried changing the vector for rotation as 2D, for example, saying to rotate around the x and y axes, but this is not equivalent to simply translating it to pi around two separate axes. Here is the nested code.


 [CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:2.0f] forKey:kCATransactionAnimationDuration]; myCard.position = CGPointMake(CGRectGetMidX(self.bounds)/2,CGRectGetMidY(self.bounds)/2); myCard.transform = CATransform3DMakeRotation(M_PI, 1, 0, 0); // rotate about x [CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:1.0f] forKey:kCATransactionAnimationDuration]; myCard.transform = CATransform3DMakeRotation(M_PI, 0, 1, 0); // rotate about y [CATransaction commit]; [CATransaction commit]; 

And here it is inside the UIView animation UIView ... I added sliders for the angle, x, y, z for the rotation vector and t for time. The translation is performed with time = 2t, and each of the turns should take only t each.

 [CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:t * 2] forKey:kCATransactionAnimationDuration]; myCard.position = CGPointMake(CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2); [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:t]; myCard.transform = CATransform3DMakeRotation(angle, x, y, z); [UIView commitAnimations]; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:t]; [UIView setAnimationDelay:t]; myCard.transform = CATransform3DMakeRotation(angle * 2, x, y, z); [UIView commitAnimations]; [CATransaction commit]; 

And this is where I am now: everything works with one exception. Rotation y changes direction (starts to rotate in the opposite direction) when the map reaches pi / 2 and 3 * pi / 2. It also flips around the x axis at these points. But x and z work fine. So close!

 CGMutablePathRef thePath = CGPathCreateMutable(); CGPathMoveToPoint(thePath,NULL,CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2*3); CGPathAddCurveToPoint(thePath,NULL, CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2*2, CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2*1.5, CGRectGetMidX(self.view.bounds)/2,CGRectGetMidY(self.view.bounds)/2); CAKeyframeAnimation *moveAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; moveAnimation.path=thePath; CFRelease(thePath); CABasicAnimation *xRotation; xRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"]; xRotation.fromValue = [NSNumber numberWithFloat:0.0]; xRotation.toValue = [NSNumber numberWithFloat:x * angle * M_PI]; CABasicAnimation *yRotation; yRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"]; yRotation.fromValue = [NSNumber numberWithFloat:0.0]; yRotation.toValue = [NSNumber numberWithFloat:y * angle * M_PI]; CABasicAnimation *zRotation; zRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; zRotation.fromValue = [NSNumber numberWithFloat:0.0]; zRotation.toValue = [NSNumber numberWithFloat:z * angle * M_PI]; CAAnimationGroup *groupAnimation = [CAAnimationGroup animation]; groupAnimation.duration = t; groupAnimation.removedOnCompletion = NO; groupAnimation.fillMode = kCAFillModeForwards; groupAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; groupAnimation.animations = [NSArray arrayWithObjects:moveAnimation, xRotation, yRotation, zRotation, nil]; [myCard addAnimation:groupAnimation forKey:@"animateCard"]; 
+2
source share
3 answers

I believe that in this case you need to use an auxiliary key as described in this answer :

 CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"]; rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI]; rotationAnimation.duration = duration; [myCard.layer addAnimation:rotationAnimation forKey:@"rotationAnimation1"]; 

which should rotate around the x axis for the first stage of your animation. Secondly, I believe that if you use the following

 CABasicAnimation *rotationAnimation2 = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"]; rotationAnimation2.toValue = [NSNumber numberWithFloat: M_PI]; rotationAnimation2.duration = duration2; rotationAnimation2.cumulative = YES; [myCard.layer addAnimation:rotationAnimation2 forKey:@"rotationAnimation2"]; 

it should make the animation cumulative and may cause the desired effect. I have not tried this myself, so you may need some intervention to get the exact result.

When you work directly with a transform, Core Animation will interpolate the transform from the current value to the specified transform. He will find the shortest path to this transformation, which will limit the direction of the animation. If you try to animate the same transform property twice, the second value will simply override the first, and not combine the two transforms together.

However, when using an auxiliary key cable like this, Core Animation will interpolate between your starting angle and the ending angle, so you can change direction by changing the sign of the ending angle. It optimizes the change in the value of the angle, and not the change in the basic transformation. You should also be able to combine animation in a key way, because a frame is created for you under the hood for each combination of keyword manipulations.

+9
source

I assume that switching to the axis is caused by a pocket lock in the Apple library. An easy fix that works 99.999% of the time is simply not to use exact rotations of 0, 90, 180, 270, and 360 degrees. I have seen things like this happening in my code, but I just use something like (M_PI * 0.99) instead of M_PI. This is always a problem if you use video card matrix multipliers with Euler angles.

To apply multiple transformations at once, you can nest them. This works just like matrix multiplication in OpenGL.

 // translate and scale at the same time float scale = 1.6; CATransform3D scaleMatrix = CATransform3DMakeScale(scale, scale, 1); CATransform3D finalMatrix = CATransform3DTranslate(scaleMatrix, frame.size.width/scale, frame.size.height/scale, 0); CABasicAnimation* animBottomTrans = [CABasicAnimation animationWithKeyPath:@"transform"]; [animBottomTrans setFromValue:[NSValue valueWithCATransform3D:finalMatrix]]; [animBottomTrans setToValue:[NSValue valueWithCATransform3D:CATransform3DIdentity]]; [animBottomTrans setDuration:duration]; [myLayer addAnimation:animBottomTrans forKey:@"transform"]; 

Remember that since they are nested, you need to deal with the previous transformation in any transformations that appear after it. In this code, I have to change the amount that I transferred, because I already scaled. If you rotate 90 degrees along the z axis and then rotate 90 degrees along the y axis, you actually just rotate along the z and x axes (z rotation changes your x and y axes).

+3
source

The resulting conversion is the same: (CGAffineTransform){-1,0,0,-1,0,0} . CoreAnimation selects the shortest rotation that will do the trick, and will rotate clockwise by default (I think).

The easiest way to turn the other way is to turn almost -M_PI (I'm not sure exactly how close you can get before he decides to turn the β€œwrong” way).

A more complicated way is to split it into two turns: one from 0 to -M_PI / 2 and one from -M_PI / 2 to -M-PI. I think you can set the animation delay for this to happen ...

+1
source

Source: https://habr.com/ru/post/898861/


All Articles