I try to implement the animation:
when you enter iPhone Gallery, press the image, you see full-screen image. Below you can see toolbar with trash button. When you press this button, the image is being deleted with animation.
I try to implement this, but I don't know, how to implement the transform of image, apple use.
This is the best, I could do:
[UIView transitionWithView:self.view duration:0.1 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[self.view addSubview:scrollImageView];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
CGRect frame = scrollImageView.frame;
frame.size = CGSizeMake(frame.size.width * 0.75, frame.size.height * 0.75);
frame.origin = CGPointMake((size.width - frame.size.width) / 2, (size.height - frame.size.height) / 2);
scrollImageView.frame = frame;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
CGRect frame = scrollImageView.frame;
frame.size = CGSizeMake(frame.size.width * 0.05, frame.size.height * 0.05);
frame.origin = CGPointMake(size.width, size.height);
scrollImageView.frame = frame;
CGAffineTransform transform = scrollImageView.transform;
CGAffineTransform rotatedTransform = CGAffineTransformRotate(transform, 45 * 3.14 / 180);
scrollImageView.transform = rotatedTransform;
} completion:^(BOOL finished) {
[scrollImageView removeFromSuperview];
}];
}];
}];
Thank you in advance.
Update
As I understand, I can't do this animation with Core-Animation, but may anyone can advice me the animation the most simular to iPhone Gallery animation, but without using OpenGL?
You can use following example for this animation:
UIView *senderView = (UIView*)sender;
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"transform"];
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anim.duration = 0.125;
anim.repeatCount = 1;
anim.autoreverses = YES;
anim.removedOnCompletion = YES;
anim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1.0)];
//[senderView.layer addAnimation:anim forKey:nil];
UIBezierPath *movePath = [UIBezierPath bezierPath];
[movePath moveToPoint:icon.center];
[movePath addQuadCurveToPoint:senderView.center
controlPoint:CGPointMake(senderView.center.x, icon.center.y)];
CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
moveAnim.path = movePath.CGPath;
moveAnim.removedOnCompletion = YES;
CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
scaleAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
scaleAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1.0)];
scaleAnim.removedOnCompletion = YES;
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:#"alpha"];
opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnim.toValue = [NSNumber numberWithFloat:0.1];
opacityAnim.removedOnCompletion = YES;
CAAnimationGroup *animGroup = [CAAnimationGroup animation];
animGroup.animations = [NSArray arrayWithObjects:moveAnim, scaleAnim, opacityAnim, nil];
animGroup.duration = 0.5;
[icon.layer addAnimation:animGroup forKey:nil];
I have modified the code, you have to perform following changes in it, set the sender view as self.view, and change the ending point of animation (which is currently senderView.center) according to your requirement
I know its a bit late. But, you should check Ciechan's solution named BCGenieEffect. Can be found here. Its pure Core Animation and very easy to understand. I think that's what you are looking for.
Good luck
At this point the exact animation you are talking about cannot be done using Core Animation or UIKit. You would need to use OpenGL and apply the image as a texture and do your animation in there.
I think you are talking about the "suck" transition animation.
It is possible to trigger it, but it is a private transition, and Apple may reject your app if you use it.
This code should do it, using a transition code of 103:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition: transtionIndex forView:containerView cache:NO];
[containerView addSubview: newView];
[oldView removeFromSuperview];
[UIView commitAnimations];
Or search the net for a Core Image transition called "suckEffect"
Related
I'm animating a clock arm from pointing towards 12 o'clock to the current time. If it is say, 11 o'clock, I want the arm to rotate clockwise to the 11 o'clock position. But of course if I use:
CGAffineTransform rotation = CGAffineTransformMakeRotation(2*M_PI*11/12);
[UIView animateWithDuration:3.0
animations:^{
clockArm.transform = rotation;
}];
the rotation goes counterclockwise. I tried:
CGFloat angle = 2*M_PI*11/12;
CGAffineTransform firstRotation = CGAffineTransformMakeRotation(M_PI-0.001);
CGFloat firstRotationTime = 3.0*(M_PI/angle);
CGAffineTransform secondRotation = CGAffineTransformMakeRotation(angle);
CGFloat secondRotationTime = 3.0 - firstRotationTime;
[UIView animateWithDuration:firstRotationTime
delay:0.0
options:UIViewAnimationCurveLinear
animations:^{
self.clockArm1.transform = firstRotation;
}
completion:^(BOOL finished) {
[UIView animateWithDuration:secondRotationTime
delay:0.0
options:UIViewAnimationCurveLinear
animations:^{
self.clockArm1.transform = secondRotation;
}
completion:^(BOOL finished){
}];
}];
The animation does go clockwise, but it is choppy - the animation still seems to be doing a UIViewAnimationEaseInOut for the first animation. What am I doing wrong, or is there another way to accomplish what I want?
You can use the completion block of CATransaction to set the rotation property of the view when the animation has finished. The following function worked in my test case:
- (void) rotateViewAnimated:(UIView*)view
withDuration:(CFTimeInterval)duration
byAngle:(CGFloat)angle
{
[CATransaction begin];
CABasicAnimation *rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.byValue = [NSNumber numberWithFloat:angle];
rotationAnimation.duration = duration;
rotationAnimation.removedOnCompletion = YES;
[CATransaction setCompletionBlock:^{
view.transform = CGAffineTransformRotate(view.transform, angle);
}];
[view.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
[CATransaction commit];
}
You use it like
[self rotateViewAnimated:self.clockArm1 withDuration:3.0 byAngle:2*M_PI*11./12.];
Thanks for #Martin R 's accepted answer. I edited a bit:
I replaced this line
rotationAnimation.removedOnCompletion = YES;
with these two lines:
rotationAnimation.removedOnCompletion = NO;
rotationAnimation.fillMode = kCAFillModeForwards;
Then, in the CompletionBlock, I added one more line:
[view.layer removeAllAnimations];
So, the code finally becomes:
- (void) rotateViewAnimated:(UIView*)view
withDuration:(CFTimeInterval)duration
byAngle:(CGFloat)angle
{
[CATransaction begin];
CABasicAnimation *rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.byValue = [NSNumber numberWithFloat:angle];
rotationAnimation.duration = duration;
// changed by me
rotationAnimation.removedOnCompletion = NO;
rotationAnimation.fillMode = kCAFillModeForwards;
[CATransaction setCompletionBlock:^{
view.transform = CGAffineTransformRotate(view.transform, angle);
// added by me
[view.layer removeAllAnimations]; // this is important
}];
[view.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
[CATransaction commit];
}
My references are from:
1, https://stackoverflow.com/a/3586433/2481444
2, After rotating a CALayer using CABasicAnimation the layer jumps back to it's unrotated position
As mentioned in comments, try this iphone UIImageView rotation
or UIView Infinite 360 degree rotation animation?
#import <QuartzCore/QuartzCore.h>
- (void) runSpinAnimationWithDuration:(CGFloat) duration;
{
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 /* full rotation*/ * rotations * duration ];
rotationAnimation.duration = duration;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 1.0;
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[myView.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
}
According to this answer there's a way to make a CGAffineTransform permanent:
iphone - making the CGAffineTransform permanent
but it's not explained... the answer tells about a copy that is generated by the animation but isn't clear how to get it and assign to the original object, so this is the code, how to make it permanent?
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
[UIView setAnimationRepeatAutoreverses:NO];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationDelegate:self];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
float angleRadians = 180 * ((float)M_PI / 180.0f);
CGAffineTransform t = CGAffineTransformMakeRotation(angleRadians);
self.myView.transform = t;
[self.myView setCenter:CGPointMake(160, 220)];
[UIView commitAnimations];
Thanks
You can try going a level down to Core Animation and apply transform animation with following properties:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform"];
animation.fromValue = [NSValue valueWithCATransform3D: t];
animation.toValue = [NSValue valueWithCATransform3D: t];
animation.duration = 0.0;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeBoth;
[yourView.layer addAnimation:animation forKey:#"transform"];
Then you can do other core animations and it should retain the transform. Don't forget to import QuartzCore framework.
In iOS 4.0 or greater Apple recommends using Block based animations
reference: What are block-based animation methods in iPhone OS 4.0?
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{ self.myView.transform = CGAffineTransformMakeRotation(M_PI) }
completion:NULL];
Not sure if this will solve your problem exactly, but it is a step in the right direction.
Given:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:card cache:NO];
myPic = [UIImage UIImagenamed: #"mySecondImage.png"];
[UIView commitAnimations];[/CODE]
Which animates 'myPic' right to left with a flip.
I need to get the same animation, but vertically. Flip from Top or Flip from Bottom. I looked around, no one really had a working model suggested.
I tried this, yet, no luck:
float duration = .5;
CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.x"];
animation.fromValue = [NSNumber numberWithDouble:0.0f * M_PI];
animation.toValue = [NSNumber numberWithDouble:1.0f * M_PI];
animation.duration = duration;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeBoth;
animation.repeatCount =1;;
animation.beginTime = CACurrentMediaTime();
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
card.layer.anchorPoint = CGPointMake(0.5, 1.0);
[card.layer addAnimation:animation forKey:#"rotationX"];[/CODE]
Any input?
Thanks in advance.
I've also needed flip from bottom animation. I've compiled couple solutions and this works for me
- (CATransform3D) makeRotationAndPerspectiveTransform:(CGFloat) angle {
CATransform3D transform = CATransform3DMakeRotation(angle, 1.0f, 0.0f, 0.0f);
transform.m34 = 1.0 / -500;
return transform;
}
- (void) flipFromBottom {
//setup firstView to be visible
view1.layer.transform = CATransform3DMakeRotation(0, 1.0f, 0.0f, 0.0f);
view1.hidden = NO;
// setup secondView to be partialy rotated and invisible
view2.layer.transform = [self makeRotationAndPerspectiveTransform:M_PI/2];
view2.hidden = YES;
// making sure that both views have the same position
view2.frame = view1.frame;
CFTimeInterval duration = 2.0;
[UIView animateWithDuration:duration/2
delay:0
options:UIViewAnimationCurveEaseIn
animations:^{
view1.layer.transform = [self makeRotationAndPerspectiveTransform:-M_PI / 2];
}
completion:^(BOOL finished){
view1.hidden = YES;
view2.hidden = NO;
[UIView animateWithDuration:duration /2
delay:0
options:UIViewAnimationCurveEaseOut
animations:^{
view2.layer.transform = CATransform3DMakeRotation(0.0f, 1.0f, 0.0f, 0.0f);
}
completion:NULL];
}];
}
I would like to present a view in the same manner as that of UIAlertView - a pop/spring. Unfortunately subclassing UIAlertView is not an option for the view I need to present. I have written some code, but I can't seem to get it as realistic as I would like. I would appreciate any suggestions for greater realism or a link if anything similar has been done (I could not find anything on Google). Thank you.
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
self.backgroundColor = [UIColor whiteColor];
v = [[UIView alloc] initWithFrame:CGRectMake(140, 140, 60, 60)];
v.backgroundColor = [UIColor blueColor];
[self addSubview:v];
[self animate];
}
return self;
}
- (void)animate {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.2];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(popStep1Complete)];
v.frame = CGRectMake(90, 90, 140, 140);
[UIView commitAnimations];
}
- (void)popStep1Complete {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.15];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(popStep2Complete)];
v.frame = CGRectMake(110, 110, 100, 100);
[UIView commitAnimations];
}
- (void)popStep2Complete {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:0.15];
v.frame = CGRectMake(100, 100, 120, 120);
[UIView commitAnimations];
}
- (void) attachPopUpAnimation
{
CAKeyframeAnimation *animation = [CAKeyframeAnimation
animationWithKeyPath:#"transform"];
CATransform3D scale1 = CATransform3DMakeScale(0.5, 0.5, 1);
CATransform3D scale2 = CATransform3DMakeScale(1.2, 1.2, 1);
CATransform3D scale3 = CATransform3DMakeScale(0.9, 0.9, 1);
CATransform3D scale4 = CATransform3DMakeScale(1.0, 1.0, 1);
NSArray *frameValues = [NSArray arrayWithObjects:
[NSValue valueWithCATransform3D:scale1],
[NSValue valueWithCATransform3D:scale2],
[NSValue valueWithCATransform3D:scale3],
[NSValue valueWithCATransform3D:scale4],
nil];
[animation setValues:frameValues];
NSArray *frameTimes = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:0.9],
[NSNumber numberWithFloat:1.0],
nil];
[animation setKeyTimes:frameTimes];
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.duration = .2;
[self.layer addAnimation:animation forKey:#"popup"];
}
the pointer to delackner's post is the best initial one i found as well. i would only offer for folks trying to really mimic UIAlertView a few things:
adding the rounded edges, border, and semi-transparent layer color
some alpha fade-in/-out, and
redoing with blocks as somewhat more succinct with latest iOS toolchain
i also found the initial 1.1 scale-out he suggests too large, 1.05 seemed more correct visually to me in most cases
Code:
self.layer.cornerRadius = 10.0;
[self.layer setMasksToBounds:YES];
self.layer.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:0.60].CGColor;
self.layer.borderColor = [UIColor whiteColor].CGColor;
self.layer.borderWidth = 1.1;
if (self.hidden == YES) { // swoop in if coming from hidden, otherwise pulse in-place
self.transform = CGAffineTransformMakeScale(0.6, 0.6);
}
self.hidden = NO;
[UIView animateWithDuration:0.2
animations:^{
self.transform = CGAffineTransformMakeScale(1.05, 1.05);
self.alpha = 0.8;
}
completion:^(BOOL finished){
[UIView animateWithDuration:1/15.0
animations:^{
self.transform = CGAffineTransformMakeScale(0.9, 0.9);
self.alpha = 0.9;
}
completion:^(BOOL finished) {
[UIView animateWithDuration:1/7.5
animations:^{
self.transform = CGAffineTransformIdentity;
self.alpha = 1.0;
}
];
}
];
}
];
One thing: multi-step animations like this are much easier if you use a CAKeyframeAnimation instead of mutiple UIView queued animations.
I'd like to "Stretch" a UIView to the right side, meaning increase it's frame.size.width by foo pixels and at the same time decreasing it's frame.origin.x by foo pixels, using [UIView beginAnimations] syntax.
However, if I do that, when the animation begins the view immediately resizes, and then starts the animation for the origin.
CGRect currFrame = someView.frame;
currFrame.size.width += 100;
currFrame.origin.x -= 100;
[UIView beginAnimations:#"Anim1" context:nil];
someView.frame = currFrame;
[UIView setAnimationDuration:0.7];
[UIView commitAnimations];
I've also tried breaking the animation down to 2 parts but then I can't keep the right position in place.
Any help is much appreciated!
You might need to drop down to Core Animation and break this into two explicit animations:
CABasicAnimation *stetchAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale.x"];
stetchAnimation.toValue = [NSNumber numberWithDouble:(someView.frame.size.width+100)/someView.frame.size.width];
CABasicAnimation *slideAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.x"];
slideAnimation.toValue = [NSNumber numberWithDouble:-100];
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = [NSArray arrayWithObjects:stetchAnimation,slideAnimation,nil];
animationGroup.removedOnCompletion = NO;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.duration = 0.7;
[someView.layer addAnimation:animationGroup forKey:#"animations"];