Im trying to animate a moving meter by rotating it more than 180 degrees, but it wont work. Im using CGAffineTransform to rotate the meter, which uses a net result to make the rotation. This means that i cannot choose CW or CCW rotation when using this function. How can I modified this code to make it rotate 4 radians. Currently the rotation is transformed to a net result, making the rotation minimal.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
CGAffineTransform transform = CGAffineTransformMakeRotation(4);
self.meter.transform = transform;
[UIView commitAnimations];
EDIT:
From the answers i managed to get it working by doing this
[UIView animateWithDuration:1.5 animations:^{
CABasicAnimation *fullRotation;
fullRotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotation.fromValue = [NSNumber numberWithFloat:0];
fullRotation.toValue = [NSNumber numberWithFloat:((330*M_PI)/180)];
fullRotation.duration = 2.0f;
fullRotation.repeatCount = 1;
fullRotation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
fullRotation.fillMode = kCAFillModeForwards;
fullRotation.removedOnCompletion = NO;
// add animation in your view
[self.meter.layer addAnimation:fullRotation forKey:#"330"];
[self performSelector:#selector(stopRotate:) withObject:self.meter afterDelay:2.0];
}];
//Add This in header prefix
#define MAXFLOAT 0x1.fffffep+127f
// add For rotation
[UIView animateWithDuration:1.5 animations:^{
CABasicAnimation *fullRotation;
fullRotation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
fullRotation.fromValue = [NSNumber numberWithFloat:0];
fullRotation.toValue = [NSNumber numberWithFloat:(2*M_PI))];
fullRotation.duration =1.0f;
fullRotation.repeatCount = MAXFLOAT;
// add animation in your view
[yourView.layer addAnimation:fullRotation forKey:#"360"];
[self performSelector:#selector(stopRotate:) withObject:yourView afterDelay:1.0];
}];
And Add this code to stop rotation From view
-(void)stopRotate :(UIView *)yourView
{
[yourView.layer removeAnimationForKey:#"360"];
}
Try this, just change the basic properties to match your requirements:
CATransform3D rotationTransform = CATransform3DMakeRotation(((4) * (180.0 / M_PI)), 0, 0, 1.0);
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
rotationAnimation.toValue = [NSValue valueWithCATransform3D:rotationTransform];
rotationAnimation.duration = 0.6f;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 1;
//Add this two lines
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.removedOnCompletion = NO;
[self.meter.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
Let me know is it works for you.
You need to convert the radian to degree using the following macro:
#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))
and pass the value to the function:
-(UIImage*)rotateImage:(UIImage*)img forAngle:(CGFloat)degree {
UIView *rotatedViewBox = [[UIView alloc]initWithFrame:CGRectMake(0, 0, img.size.width, img.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(degree);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, rotatedSize.width, rotatedSize.height);
CGContextRotateCTM(context, radian);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(-img.size.width, -img.size.height, img.size.width, img.size.height), img.CGImage);
UIImage *returnImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return returnImg;
}
Related
I want to implement an animation, its like from a point view starts expanding circularly and filling the entire view. I have implemented the following code but it does not fill the view circularly. Any ideas?
- (void)viewDidLoad {
[super viewDidLoad];
myView =[[UIView alloc]init];
myView.frame=CGRectMake(self.view.frame.size.width/2,self.view.frame.size.height/2+100, .1, .1);
myView.backgroundColor=[UIColor redColor];
[self.view addSubview:myView];
[self animate];
}
-(void)animate{
[UIView animateWithDuration:1.0
delay: 0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self setRoundedView: myView toDiameter:1000];
}
completion:nil];
}
-(void)setRoundedView:(UIView *)roundedView toDiameter:(float)newSize;
{
CGPoint saveCenter = roundedView.center;
CGRect newFrame = CGRectMake(roundedView.frame.origin.x, roundedView.frame.origin.y, newSize, newSize);
roundedView.frame = newFrame;
roundedView.layer.cornerRadius = newSize / 2.0;
roundedView.center = saveCenter;
}
You can create a CAShape layer with circular Bezier Path and animate the path property.
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath: #"path"];
Check here for more details : Animating CAShapeLayer size change
If you dont want to use CAnimation you can just scale your rounded view like this :
[UIView animateWithDuration:1.0
delay: 0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
myView.transform = CGAffineTransformMakeScale(scaleX,scaleY);
}
completion:nil];
Try this code. May be helpful.
// Set up the shape of the circle
int radius = 100;
CAShapeLayer *circle = [CAShapeLayer layer];
// Make a circular shape
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius)
cornerRadius:radius].CGPath;
// Center the shape in self.view
circle.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
CGRectGetMidY(self.view.frame)-radius);
// Configure the apperence of the circle
circle.fillColor = [UIColor redColor].CGColor;
circle.strokeColor = [UIColor blackColor].CGColor;
circle.lineWidth = 5;
// Add to parent layer
[self.view.layer addSublayer:circle];
// Configure animation
CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:#"strokeEnd"];
drawAnimation.duration = 10.0; // "animate over 10 seconds or so.."
drawAnimation.repeatCount = 1.0; // Animate only once..
// Animate from no part of the stroke being drawn to the entire stroke being drawn
drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
drawAnimation.toValue = [NSNumber numberWithFloat:1.0f];
// Experiment with timing to get the appearence to look the way you want
drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
// Add the animation to the circle
[circle addAnimation:drawAnimation forKey:#"drawCircleAnimation"];
I am trying to get an image to go full screen, and if the image is landscape then rotate it as it grows.
The code to make it fullscreen works ok, but if I add in the rotation the results are rather unpredictable and the image rotates, moves to the left hand side but does not grow fullscreen.
Code used is:
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
previousFrame = imgView.frame;
[imgView setFrame:[[UIScreen mainScreen] bounds]];
imgView.backgroundColor = [UIColor blackColor];
[imgView.layer setBorderWidth: 0.0];
if(imgView.image.size.width > imgView.image.size.height)
imgView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90));
}
completion:^(BOOL finished){
isFullScreen = YES;
}
];
Not sure what I am missing here, but assuming maybe something to do with rotation and the image view bounds?
Try to use CABasicAnimation instead, combine these examples:
Size example:
-(void)resizeLayer:(CALayer*)layer to:(CGSize)size
{
CGRect oldBounds = layer.bounds;
CGRect newBounds = oldBounds;
newBounds.size = size;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"bounds"];
animation.fromValue = [NSValue valueWithCGRect:oldBounds];
animation.toValue = [NSValue valueWithCGRect:newBounds];
animation.duration = animationspeed;
progressLayer.anchorPoint = CGPointMake(0, progressLayer.anchorPoint.y);
layer.bounds = newBounds;
[layer addAnimation:animation forKey:#"bounds"];
}
Rotation example:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
animation.duration = 5;
animation.additive = YES;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.fromValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(0)];
animation.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(90)];
[self.imgView.layer addAnimation:animation forKey:#"90rotation"];
Combine them with an animationgroup, example:
// Animation group
CAAnimationGroup* group = [CAAnimationGroup animation];
group.animations = [NSArray arrayWithObjects:colorAnim, widthAnim, nil];
group.duration = 5.0;
[myLayer addAnimation:group forKey:#"BorderChanges"];
Can you try this code
[UIView animateWithDuration:0.5 delay:0 options:0 animations:^{
//save previous frame
previousFrame = imgView.frame;
[imgView setFrame:[[UIScreen mainScreen] bounds]];
imgView.backgroundColor = [UIColor blackColor];
[imgView.layer setBorderWidth: 0.0];
}
completion:^(BOOL finished){
if(imgView.image.size.width > imgView.image.size.height)
imgView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90));
isFullScreen = YES;
}
];
I'm trying to do a 360 spin of a view but at a 45 degree tilt.
Like this
I can't figure out for to do it.
So far I've managed this
CABasicAnimation* animation = [CABasicAnimation
animationWithKeyPath:#"transform.rotation.y"];
animation.fromValue = #(0);
animation.toValue = #(2 * M_PI);
animation.duration = 1;
[self.layer addAnimation:animation forKey:#"rotation"];
Which spins it on it's y axis, but what I want is for this Y axis to be tilted 45 degree before it's spun.
First, you should see the link below which explains that the differences between "frame" and "bounds".
UIView frame, bounds and center
And now, here is my answer.
/* add the 4 lines below */
self.transform = CGAffineTransformMakeRotation(M_PI_4);
self.layer.bounds = CGRectMake(0.0f, 0.0f, 60.0f, 200.0f);
self.layer.position = CGPointMake(150.0f, 300.0f);
CABasicAnimation* animation = [CABasicAnimation
animationWithKeyPath:#"transform.rotation.y"];
animation.fromValue = #(0);
animation.toValue = #(2 * M_PI);
animation.duration = 1;
[self.layer addAnimation:animation forKey:#"rotation"];
try this;
CABasicAnimation* animation = [CABasicAnimation
animationWithKeyPath:#"transform"];
CATransform3D rtfm = CATransform3DMakeRotation(2 * M_PI , 1.0f, 1.0f, 0.0f);
rtfm.m34 = -0.0015f;
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
animation.toValue = [NSValue valueWithCATransform3D:rtfm];
animation.duration = 1;
[self.layer addAnimation:animation forKey:#"rotation"];
1- Change the anchor point to the upper right edge
self.someView.layer.anchorPoint = CGPointMake(1.0, 0.5);
2- rotate the view by 45 or 35 degrees
CGFloat radians = (M_PI/180) * (-35);
self.someView.transform = CGAffineTransformRotate(self.someView.transform, radians);
3- rotate or flip your view by X axis
CGFloat radians = (M_PI/180) * (180);
[UIView animateWithDuration:1 animations:^{
self.someView.layer.transform = CATransform3DRotate(self.someView.layer.transform,radians , 1, 0.0, 0.0);
} completion:^(BOOL finished) {
if(finished) {
}
}];
Works like a charm :)
I have the following code that rotates a CALayer by -45degrees on the Y axis:
#define D2R(x) (x * (M_PI/180.0))
- (void) swipe:(UISwipeGestureRecognizer *)recognizer
{
CATransform3D transform = CATransform3DMakeRotation(D2R(-45), 0, 1.0, 0);
transform.m34 = -1.0 / 850;
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath: #"transform"];
transformAnimation.fillMode = kCAFillModeForwards;
transformAnimation.removedOnCompletion = NO;
transformAnimation.toValue = [NSValue valueWithCATransform3D:transform];
transformAnimation.duration = 0.5;
[self.layer addAnimation:transformAnimation forKey:#"transform"];
}
The animation works, except it ends with no perspective - ignoring my m34 setting if I'm understanding things correctly.
Halfway through:
At the end:
What am I doing wrong?
Animation only affects the appearance of the view during the animation. It doesn't get applied to the view after the animation ends. You need to do this yourself. I'm guessing something like this right after adding the animation will work:
self.layer.transform = transform;
You can do this right away, as the animation will hide it until the animation completes.
Try this :
- (void) swipe:(UISwipeGestureRecognizer *)recognizer
{
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -10 / 850.0;
transform = CATransform3DRotate(transform, D2R(-45), 0, 1.0, 0);
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath: #"transform"];
transformAnimation.fillMode = kCAFillModeForwards;
transformAnimation.removedOnCompletion = NO;
transformAnimation.toValue = [NSValue valueWithCATransform3D:transform];
transformAnimation.duration = 0.5;
[self.layer addAnimation:transformAnimation forKey:#"transform"];
}
And end the effect is like this :
I am using a simple transformation animation to an UIIMageView.
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveEaseInOut animations:^{
CGAffineTransform translate = CGAffineTransformMakeTranslation(0, -[self percentFromHeight:20]);
clueImage.transform = translate;
} completion:^(BOOL finished) {
[self.cluWordSelectionView setaWordsObjects:[NSArray arrayWithArray:[self.whiteCard clueWordObjectsForSoundAtIndex:self.index]]];
[self addSubview:cluWordSelectionView];
[clueImage.layer addAnimation:[Animations shakeAnimation] forKey:#"shake"];
}];
As you can see after the completion I am adding an other shake animation to the view:
[clueImage.layer addAnimation:[Animations shakeAnimation] forKey:#"shake"];
Which looks like that:
+(CAAnimation*)shakeAnimation {
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
CGFloat wobbleAngle = 0.06f;
NSValue* valLeft = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f)];
NSValue* valRight = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f)];
animation.values = [NSArray arrayWithObjects:valLeft, valRight, nil];
animation.beginTime = 3;
animation.autoreverses = YES;
animation.duration = 0.125;
animation.repeatCount = HUGE_VALF;
return animation;
}
The problem is that when the shakeAnimation starts the view "jumps" back to it's original position. How can I prevent that and Why this is happening?
Thanks
shani
The new animation should take the current transform (translation) into account:
CATransform3D leftTransform = CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f);
leftTransform = CATransform3DConcat(layer.transform, leftTransform);
CATransform3D rightTransform = CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f);
rightTransform = CATransform3DConcat(layer.transform, rightTransform);
NSValue* valLeft = [NSValue valueWithCATransform3D:leftTransform];
NSValue* valRight = [NSValue valueWithCATransform3D:rightTransform];
Where layer is the layer that will be animated.