iOS view transform animation - objective-c

I'm probably missing something simple, but trying to do a simple "Ken Burns Effect" with an image view.
First the code:
[UIView animateWithDuration:20
delay:2
options:UIViewAnimationCurveLinear
animations:^{
CGAffineTransform move = CGAffineTransformMakeTranslation(40, 40);
CGAffineTransform zoom = CGAffineTransformMakeScale(1.2, 1.2);
CGAffineTransform transform = CGAffineTransformConcat(zoom, move);
self.imageView.transform = transform;
}
completion:^(BOOL finished){
NSLog(#"Done");
}];
I expected this to start with the image view at normal scale and expand it to 120% of the size over 20 seconds. What actually happens is that it starts out immediately smaller than normal size, then expands to normal size.
If I use the reciprocal of the scale value, it starts out zoomed in and then zooms out to normal scale which is the opposite of the effect I want.
Any ideas?

Ok, this actually worked and does what I want.
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
transformAnimation.duration = 20.0;
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transformAnimation.removedOnCompletion = NO;
transformAnimation.fillMode = kCAFillModeForwards;
CATransform3D xform = CATransform3DIdentity;
xform = CATransform3DScale(xform, 1.2, 1.2, 1.0);
xform = CATransform3DTranslate(xform, 60, -60, 0);
transformAnimation.toValue = [NSValue valueWithCATransform3D:xform];
[self.imageView.layer addAnimation:transformAnimation forKey:#"transformAnimation"];

It sounds like the view is being re-laid out by its parent view in response to the change in transform, casing it to be scaled down to the end result of the transform as soon as the transform is set in the animation block. The key is that your first attempt makes changes directly to the view, while the second approach works with the layer.

Have you try starting form the current transform of your imageView ?
[UIView animateWithDuration:20
delay:2
options:UIViewAnimationCurveLinear
animations:^{
CGAffineTransform trans = self.imageView.transform;
CGAffineTransformTranslate(trans, 40, 40);
CGAffineTransformScale(trans, 1.2, 1.2);
self.imageView.transform = trans;
}
completion:^(BOOL finished){
NSLog(#"Done");
}];

Related

UIView animation to move and back

I would like to have animation on a view, that it will go 2 pixels right on x, and 2 pixels back left on x .
I have this for opacity, and i am looking to adjust this to make it ,
CABasicAnimation *theAnimation;
theAnimation=[CABasicAnimation animationWithKeyPath:#"opacity"];
theAnimation.duration=1.0;
theAnimation.repeatCount=HUGE_VALF;
theAnimation.autoreverses=YES;
theAnimation.fromValue=[NSNumber numberWithFloat:1.0];
theAnimation.toValue=[NSNumber numberWithFloat:0.3];
[image.layer addAnimation:theAnimation forKey:#"animateOpacity"];
If you just want the animation to occur once then you can jump up a few levels of abstraction and use the block based view animations
[UIView animateWithDuration:1.f
delay:0
options:UIViewAnimationOptionAutoreverse
animations:^{
view.transform = CGAffineTransformMakeTranslation(2.f, 0.f);
} completion:^(BOOL finished) {
view.transform = CGAffineTransformIdentity;
}];
This applies a translation of two points right and then removes it on completion

Move and resize UILabel with CGAfficeTransform

Basically I want to move a UILabel up 20px and resize it to 55% of it's original size.
=> x stays the same, y,height, width decrease.
What I came up is following :
//_line a UILabel*
CGFloat scaleFactor = 0.55f;
[UIView animateWithDuration:1.0 animations:^{
CGAffineTransform transform = CGAffineTransformMakeTranslation(0, -20);
transform = CGAffineTransformScale(transform, scaleFactor, scaleFactor);
_line.transform = transform;
}];
Unfortunately I don't get the expected result. It (slightly) moves up but also moves to the right.
What am I missing ?
The problem is that you're using Auto Layout. Auto Layout and view transforms are enemies of one another. You perform the transform, but then Auto Layout kicks in and changes the frame of the label essentially back to what it was.
The problem is that you're overwriting the transform. You initially set transform to the translation transformation, and then before anything has happened you reset it to the scale transformation. So all it's doing is the scale action.
Instead you need to combine the two matrices and store their combination into transform. Try this:
CGFloat scaleFactor = 0.55f;
[UIView animateWithDuration:1.0 animations:^{
CGAffineTransform translationTransform = CGAffineTransformMakeTranslation(0, -20);
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
CGAffineTransform totalTransform = CGAffineTransformConcat(translationTransform, scaleTransform);
_line.transform = totalTransform;
}];
This did the job fob me : a second translation
CGFloat scaleFactor = 0.55f;
CGFloat x_delta = _line.frame.size.width * (1-scaleFactor);
CGFloat y_delta = _line.frame.size.height * (1-scaleFactor);
[UIView animateWithDuration:1.0 animations:^{
CGAffineTransform transform = CGAffineTransformMakeTranslation(0, -20);
transform = CGAffineTransformScale(transform, scaleFactor, scaleFactor);
transform = CGAffineTransformTranslate(transform, -x_delta, -y_delta);
_line.transform = transform;
}];

How do i shrink an image horizontally using CGAffineTransform?

I've been using CABasicAnimation to move around images. Now I need to take a view and shrink it horizontally. On the web I see some people using CGAffineTransform to shrink/grow images proportionally. I need the view to shrink horizontally ONLY. See image below:
Any help with this would be greatly appreciated!
CGAffineTransformMakeScale(sx,sy) will do the work.
CGAffineTransform a = CGAffineTransformMakeScale(0.4, 1.0);
editingView.transform = a;
You can use [UIView animateWithDuration:animations:completion:]; if you want it to be animated.
CGAffineTransform a = CGAffineTransformMakeScale(0.4, 1.0);
[UIView animateWithDuration:0.5
animations:^{
editingView.transform = a;
}
completion:^(BOOL finished) {
/* do something after the animation */
}];

CATransform3D UIView animateWithDuration sequence

I'm a Core Animation beginner trying to animate a view in 3D sequentially. However, I'm running into issues with the 2nd animation. Essentially, once the view rotates and translates to a certain point, I'm making another translation.
When I run it, it seems like it's working, but the second animation translates the view to its destination but then returns to its initial position! It is as if a 3rd phantom animation happens to return the view to its initial state.
Can someone explain why this is happening and how I can fix it?
Thank you!
CATransform3D translation = CATransform3DMakeTranslation(0.0, -50.0, 0.0);
translation.m34 = 1.0 / -500.0f;
CATransform3D finalTransform = CATransform3DRotate(translation, 90.0f, 1.0, 0.0, 0.0);
[UIView animateWithDuration:2.0f animations:^{
[viewImageScroll.layer setTransform:finalTransform];
} completion:^(BOOL finished) {
CATransform3D flyAway = CATransform3DMakeTranslation(0., 0., -10000);
[UIView animateWithDuration:3.0f animations:^{
NSLog(#"done");
[viewImageScroll.layer setTransform:flyAway];
} completion:^(BOOL finished) {
NSLog(#"done and done");
}];
}];

Animate Rotation/Scale/Translate of UIImage at the same time

I am new to objective-c and I want to add an image to the screen, tweening it like in AS3, moving it from one end to the other of the screen while rotating around its own center point.
I tried with
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
// TRANSFORM SCREENSHOT
screenShotView.transform = CGAffineTransformRotate(screenShotView.transform, -M_PI * 0.05);
screenShotView.transform = CGAffineTransformScale(screenShotView.transform, 0.6, 0.6);
screenShotView.transform = CGAffineTransformTranslate(screenShotView.transform,
self.webView.frame.origin.x,
self.webView.frame.origin.y - self.webView.frame.size.height * 0.3
);
but with this code the image rotates around the center of the TransformIdentity. So while rotating and moving the rotation gets out of controll and the image isn't exactly at the position I loved it to be.
What is the right way to rotate and translate at the same time, translating the rotation center with the image?
and at least after transformation I want to add a close button to the right upper corner of the image. for that I need the new coordinates of the corner, too.
thnx!
I now ended with the following code, but I still don't know if this is the state of the art solution.
CGAffineTransform translate = CGAffineTransformMakeTranslation(self.webView.frame.origin.x,self.webView.frame.origin.y - self.webView.frame.size.height * 0.25);
CGAffineTransform scale = CGAffineTransformMakeScale(0.6, 0.6);
CGAffineTransform transform = CGAffineTransformConcat(translate, scale);
transform = CGAffineTransformRotate(transform, degreesToRadians(-10));
[UIView beginAnimations:#"MoveAndRotateAnimation" context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:2.0];
screenShotView.transform = transform;
[UIView commitAnimations];
IOS 7's preferred way to do this would be using a block object. It has several advantages compared to the 'older' way of animating. Especially that it can make use of multi-core and video co-processing. Also the 'built-in' call back part (the completion part) is very useful, as it keeps any necessary state information and links to objects as needed.
CGAffineTransform translate = CGAffineTransformMakeTranslation(self.webView.frame.origin.x,self.webView.frame.origin.y - self.webView.frame.size.height * 0.25);
CGAffineTransform scale = CGAffineTransformMakeScale(0.6, 0.6);
CGAffineTransform transform = CGAffineTransformConcat(translate, scale);
transform = CGAffineTransformRotate(transform, degreesToRadians(-10));
// animation using block code
[UIView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
screenShotView.transform = transform;
}completion:^(BOOL finished){
// do something if needed
}];