Shake visual effect on iPhone (NOT shaking the device) - iphone

On login failure, I'd prefer to avoid showing an alert, it's too fleeting. Showing the alert and then showing the text somewhere on the login screen seems like duplication.
So I'd like for it to graphically shake my login view when the user enters the wrong user ID and password like the Mac login screen does.
Anyone know if there's a way to pull this off, or have any suggestions for another effect I could use?

I think this is a more efficient solution:
Swift:
let anim = CAKeyframeAnimation( keyPath:"transform" )
anim.values = [
NSValue( CATransform3D:CATransform3DMakeTranslation(-5, 0, 0 ) ),
NSValue( CATransform3D:CATransform3DMakeTranslation( 5, 0, 0 ) )
]
anim.autoreverses = true
anim.repeatCount = 2
anim.duration = 7/100
viewToShake.layer.addAnimation( anim, forKey:nil )
Obj-C:
CAKeyframeAnimation * anim = [ CAKeyframeAnimation animationWithKeyPath:#"transform" ] ;
anim.values = #[
[ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-5.0f, 0.0f, 0.0f) ],
[ NSValue valueWithCATransform3D:CATransform3DMakeTranslation( 5.0f, 0.0f, 0.0f) ]
] ;
anim.autoreverses = YES ;
anim.repeatCount = 2.0f ;
anim.duration = 0.07f ;
[ viewToShake.layer addAnimation:anim forKey:nil ] ;
Only one animation object is created and it's all performed at the CoreAnimation level.

Using iOS 4+ block based UIKit animations (and loosely based on on jayccrown's answer):
- (void)shakeView:(UIView *)viewToShake
{
CGFloat t = 2.0;
CGAffineTransform translateRight = CGAffineTransformTranslate(CGAffineTransformIdentity, t, 0.0);
CGAffineTransform translateLeft = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, 0.0);
viewToShake.transform = translateLeft;
[UIView animateWithDuration:0.07 delay:0.0 options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^{
[UIView setAnimationRepeatCount:2.0];
viewToShake.transform = translateRight;
} completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.05 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
viewToShake.transform = CGAffineTransformIdentity;
} completion:NULL];
}
}];
}

I had seen some wobble animation and changed it to shake a view t pixels upright and downleft:
- (void)earthquake:(UIView*)itemView
{
CGFloat t = 2.0;
CGAffineTransform leftQuake = CGAffineTransformTranslate(CGAffineTransformIdentity, t, -t);
CGAffineTransform rightQuake = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, t);
itemView.transform = leftQuake; // starting point
[UIView beginAnimations:#"earthquake" context:itemView];
[UIView setAnimationRepeatAutoreverses:YES]; // important
[UIView setAnimationRepeatCount:5];
[UIView setAnimationDuration:0.07];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(earthquakeEnded:finished:context:)];
itemView.transform = rightQuake; // end here & auto-reverse
[UIView commitAnimations];
}
- (void)earthquakeEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
if ([finished boolValue])
{
UIView* item = (UIView *)context;
item.transform = CGAffineTransformIdentity;
}
}

Here's a tutorial that details how to do it in Cocoa. Should be the same for the iPhone (or at least quite similar).
http://www.cimgf.com/2008/02/27/core-animation-tutorial-window-shake-effect/

Simply changing the X coordinate of the center property of your view might do the trick. If you haven't done any core animation before it's pretty straight-forward.
First, start an animation right, then listen for it to finish, and then move back to the left, and so on. Getting the timing down so it "feels right" might take a while.
- (void)animationFinishCallback:(NSString *)animationID finished:(BOOL)finished context:(void *)context
{
if ([animationID isEqualToString:#"MoveRight"]) {
[UIView beginAnimations:#"MoveLeft" context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelay: UIViewAnimationCurveEaseIn];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationFinishCallback:finished:context:)];
myView.center = CGRectMake(newX, newY);
[UIView commitAnimations];
}
}

This UIView category snippet worked for me. It's using 3 CABasingAnimations applied to view's layer.
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#define Y_OFFSET 2.0f
#define X_OFFSET 2.0f
#define ANGLE_OFFSET (M_PI_4*0.1f)
#interface UIView (shakeAnimation)
-(BOOL)isShakeAnimationRunning;
-(void)startShakeAnimation;
-(void)stopShakeAnimation;
#end
#implementation UIView (shakeAnimation)
-(BOOL)isShakeAnimationRunning{
return [self.layer animationForKey:#"shake_rotation"] != nil;
}
-(void)startShakeAnimation{
CFTimeInterval offset=(double)arc4random()/(double)RAND_MAX;
self.transform=CGAffineTransformRotate(self.transform, -ANGLE_OFFSET*0.5);
self.transform=CGAffineTransformTranslate(self.transform, -X_OFFSET*0.5f, -Y_OFFSET*0.5f);
CABasicAnimation *tAnim=[CABasicAnimation animationWithKeyPath:#"position.x"];
tAnim.repeatCount=HUGE_VALF;
tAnim.byValue=[NSNumber numberWithFloat:X_OFFSET];
tAnim.duration=0.07f;
tAnim.autoreverses=YES;
tAnim.timeOffset=offset;
[self.layer addAnimation:tAnim forKey:#"shake_translation_x"];
CABasicAnimation *tyAnim=[CABasicAnimation animationWithKeyPath:#"position.y"];
tyAnim.repeatCount=HUGE_VALF;
tyAnim.byValue=[NSNumber numberWithFloat:Y_OFFSET];
tyAnim.duration=0.06f;
tyAnim.autoreverses=YES;
tyAnim.timeOffset=offset;
[self.layer addAnimation:tyAnim forKey:#"shake_translation_y"];
CABasicAnimation *rAnim=[CABasicAnimation animationWithKeyPath:#"transform.rotation"];
rAnim.repeatCount=HUGE_VALF;
rAnim.byValue=[NSNumber numberWithFloat:ANGLE_OFFSET];
rAnim.duration=0.15f;
rAnim.autoreverses=YES;
rAnim.timeOffset=offset;
[self.layer addAnimation:rAnim forKey:#"shake_rotation"];
}
-(void)stopShakeAnimation{
[self.layer removeAnimationForKey:#"shake_translation_x"];
[self.layer removeAnimationForKey:#"shake_translation_y"];
[self.layer removeAnimationForKey:#"shake_rotation"];
[UIView animateWithDuration:0.2f animations:^{
self.transform=CGAffineTransformRotate(self.transform, ANGLE_OFFSET*0.5);
self.transform=CGAffineTransformTranslate(self.transform, X_OFFSET*0.5, Y_OFFSET*0.5f);
}];
}
#end
Hope it helpes someone :)

In iOS 7.0 or later, UIKit keyframe animation is available.
[UIView animateKeyframesWithDuration:0.5 delay:0.0 options:0 animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
NSInteger repeatCount = 8;
NSTimeInterval duration = 1.0 / (NSTimeInterval)repeatCount;
for (NSInteger i = 0; i < repeatCount; i++) {
[UIView addKeyframeWithRelativeStartTime:i * duration relativeDuration:duration animations:^{
CGFloat dx = 5.0;
if (i == repeatCount - 1) {
viewToShake.transform = CGAffineTransformIdentity;
} else if (i % 2) {
viewToShake.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -dx, 0.0);
} else {
viewToShake.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, +dx, 0.0);
}
}];
}
} completion:completion];

very easy shake categorie for UIVoew
https://github.com/jonasschnelli/UIView-I7ShakeAnimation

I know the question is already answered, but since I have already implemented something like this previously, I feel it can't hurt to add it:
CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation.z"];
NSArray *transformValues = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:((M_PI)/64)],
[NSNumber numberWithFloat:(-((M_PI)/64))],
[NSNumber numberWithFloat:((M_PI)/64)],
[NSNumber numberWithFloat:(-((M_PI)/64))],
[NSNumber numberWithFloat:((M_PI)/64)],
[NSNumber numberWithFloat:(-((M_PI)/64))],
[NSNumber numberWithFloat:0],
nil];
[shakeAnimation setValues:transformValues];
NSArray *times = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.14f],
[NSNumber numberWithFloat:0.28f],
[NSNumber numberWithFloat:0.42f],
[NSNumber numberWithFloat:0.57f],
[NSNumber numberWithFloat:0.71f],
[NSNumber numberWithFloat:0.85f],
[NSNumber numberWithFloat:1.0f],
nil];
[shakeAnimation setKeyTimes:times];
shakeAnimation.fillMode = kCAFillModeForwards;
shakeAnimation.removedOnCompletion = NO;
shakeAnimation.duration = 0.6f;
[self.viewToShake.layer addAnimation:shakeAnimation forKey:#"anim"];
Also, since you want the shaking to indicate that the user failed to log in, you might also consider adding this animation that tints the screen red while the screen shakes:
//Put this in the header (.h)
#property (nonatomic, strong) UIView *redView;
//Put this in the implementation (.m)
#synthesize redView;
//Put this in viewDidLoad
self.redView = [[UIView alloc] initWithFrame:self.view.frame];
self.redView.layer.opacity = 0.0f;
self.redView.layer.backgroundColor = [[UIColor redColor] CGColor];
//Put this wherever you check if the login failed
CAKeyframeAnimation *redTint = [CAKeyframeAnimation animationWithKeyPath:#"opacity"];
NSArray *transformValues = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.2f],
[NSNumber numberWithFloat:0.0f],
nil];
[redTint setValues:transformValues];
NSArray *times = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.5f],
[NSNumber numberWithFloat:1.0f],
nil];
[redTint setKeyTimes:times];
redTint.fillMode = kCAFillModeForwards;
redTint.removedOnCompletion = NO;
redTint.duration = 0.6f;
[self.redView.layer addAnimation:shakeAnimation forKey:#"anim"];
Hope this helps!

Using Auto Layout, I adapted Chris Miles' answer but animated NSLayoutConstraints like this:
NSLayoutConstraint *left = ...
NSLayoutConstraint *right = ...
[UIView animateWithDuration:0.08 delay:0.0 options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^{
[UIView setAnimationRepeatCount:3];
left.constant = 15.0;
right.constant = 25.0;
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
if (finished) {
[UIView animateWithDuration:0.08 animations:^{
left.constant = 20.0;
right.constant = 20.0;
[self.view layoutIfNeeded];
} completion:NULL];
}
}];

A solution I used for constraints which I set in my storyboard. Without using animateWithDuration.
#IBOutlet var balloonHorizontalConstraint: NSLayoutConstraint!
NSTimer.scheduledTimerWithTimeInterval(0.04, target: self, selector: "animateBalloon", userInfo: nil, repeats: true)
func animateBalloon() {
switch balloonHorizontalConstraint.constant {
case -46:
balloonHorizontalConstraint.constant = -50
default:
balloonHorizontalConstraint.constant = -46
}
}
In my case the animation just kept on going, but I pop my viewcontroller after a duration of a few seconds, this stops my timer aswell.

Related

Fade-In Fade-Out Animation for UIImageViews?

I have two UIImageView - leftSide and rightSide, which I would like to fade in and then fade out, one after the other, in a loop.
How do I do this in Xcode? I tried CABasicAnimation but this did not work (I'm not sure why, no errors at all, the images do not fade).
Thanks!
EDIT: This is the code I was using:
-(void)leftSideFade{
CABasicAnimation *blink;
blink = [CABasicAnimation animationWithKeyPath:#"opacity"];
blink.duration = 1.0;
blink.repeatCount = 5;
blink.autoreverses = YES;
blink.fromValue = [NSNumber numberWithFloat:1.0];
blink.toValue = [NSNumber numberWithFloat:0.0];
[leftSideStart.layer addAnimation:blink forKey:#"animateOpacity"];
[self rightSideFade];
}
-(void)rightSideFade{
CABasicAnimation *blink;
blink = [CABasicAnimation animationWithKeyPath:#"opacity"];
blink.duration = 1.0;
blink.repeatCount = 5;
blink.autoreverses = YES;
blink.fromValue = [NSNumber numberWithFloat:1.0];
blink.toValue = [NSNumber numberWithFloat:0.0];
[rightSideStart.layer addAnimation:blink forKey:#"animateOpacity"];
[self leftSideFade];
}
- (void)fadeIn
{
[UIView beginAnimations:#"fadeIn Animation" context:nil];
[UIView setAnimationDuration:1.0];
imageView.alpha = 1.0;
[UIView commitAnimations];
}
Try this to.
Try using the following :
- (void) fadeinRightFadwOutLeft {
[UIView beginAnimations:#"start" context:nil];
[UIView setAnimationDuration:1.0];
rightSide.alpha = 0.0;
leftSide.alpha = 1.0;
[UIView commitAnimations];
}
- (void) fadeinLeftFadwOutRight {
[UIView beginAnimations:#"start" context:nil];
[UIView setAnimationDuration:1.0];
leftSide.alpha = 0.0;
rightSide.alpha = 1.0;
[UIView commitAnimations];
}
How about a simpler way with UIView animateWithDuration:animations:completion: ?
There you just change alpha of your views and they will fade in/out
Here is a sample code:
[UIView animateWithDuration:duration
animations:^
{
//Here you set values you want to see in the end of animation
leftView.alpha = 0.0f;
rightView.alpha = 1.0f;
}
completion:^(BOOL finished)
{
//something to do after animation finished
}

Animation, like when you delete from iPhone Photo Gallery

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"

UIVIew Flip Vertical Animation

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

Animate Rotating UIImageView

I want to rotate a UIImageView by roughly 10 degrees left/right but have a smooth animation, rather than a sudden turn which I see using:
player.transform = CGAffineTransformMakeRotation(angle)
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25]; // Set how long your animation goes for
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
player.transform = CGAffineTransformMakeRotation(angle); // if angle is in radians
// if you want to use degrees instead of radians add the following above your #implementation
// #define degreesToRadians(x)(x * M_PI / 180)
// and change the above code to: player.transform = CGAffineTransformMakeRotation(degreesToRadians(angle));
[UIView commitAnimations];
// The rotation code above will rotate your object to the angle and not rotate beyond that.
// If you want to rotate the object again but continue from the current angle, use this instead:
// player.transform = CGAffineTransformRotate(player.transform, degreesToRadians(angle));
I use some code like this to achieve a similar effect (though I rotate it by 360 degrees):
CABasicAnimation *rotate;
rotate = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
rotate.fromValue = [NSNumber numberWithFloat:0];
rotate.toValue = [NSNumber numberWithFloat:deg2rad(10)];
rotate.duration = 0.25;
rotate.repeatCount = 1;
[self.view.layer addAnimation:rotate forKey:#"10"];
I use code very similar to this to spin an image view.
Converted for Swift 3/4:
let animation = CABasicAnimation(keyPath: "transform.rotation")
animation.fromValue = 0
animation.toValue = Double.pi * 2.0
animation.duration = 2
animation.repeatCount = .infinity
animation.isRemovedOnCompletion = false
imageView.layer.add(animation, forKey: "spin")
i have some code rotate 360 degrees:
- (void) runSpinAnimationOnView:(UIView*)view duration:(CGFloat)duration rotations:(CGFloat)rotations repeat:(float)repeat;
{
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat: rotations * 2.0 /* full rotation*/ * rotations * duration ];
rotationAnimation.duration = duration;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = repeat;
[view.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
}
call it: [self runSpinAnimationOnView:imgView duration:0.1 rotations:M_PI_4 repeat:10];
And animation rotate some degrees and again:
- (void)rotateImage:(UIImageView *)image duration:(NSTimeInterval)duration delay:(NSTimeInterval)delay
curve:(int)curve rotations:(CGFloat)rotations
{
[UIView animateWithDuration:duration
delay:delay
options:0
animations:^{
[UIView setAnimationCurve:curve];
image.transform = CGAffineTransformMakeRotation(rotations);
}
completion:^(BOOL finished){
[self rotateImage2:image duration:duration delay:delay curve:curve rotations:rotations];
;
}];
[UIView commitAnimations];
}
- (void)rotateImage2:(UIImageView *)image duration:(NSTimeInterval)duration delay:(NSTimeInterval)delay
curve:(int)curve rotations:(CGFloat)rotations
{
[UIView animateWithDuration:duration
delay:delay
options:0
animations:^{
[UIView setAnimationCurve:curve];
image.transform = CGAffineTransformMakeRotation(-rotations);
}
completion:^(BOOL finished){
[self rotateImage:image duration:duration delay:delay curve:curve rotations:rotations];
;
}];
[UIView commitAnimations];
}
If you want to rotate a uiimageview by roughly 10 degrees left/right
call : [self rotateImage:imgView duration:0.7 delay:0.0 curve:UIViewAnimationCurveEaseIn rotations:(M_PI/18)];
similar, some degress
A modern Swift solution, using NSTimer and CGAffineTransformMakeRotation:
class Rotation: UIViewController {
var timer = NSTimer()
var rotAngle: CGFloat = 0.0
#IBOutlet weak var rotationImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
activateTimer()
}
func activateTimer() {
//(1)
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target:self, selector:#selector(Rotation.updateCounter), userInfo: nil, repeats: true)
}
func updateCounter() {
//(2)
var rotateLeft: Bool = true
if rotateLeft {
rotAngle -= 30.0
} else {
rotAngle += 30.0
}
//(3)
UIView.animateWithDuration(2.0, animations: {
self.rotationImage.transform = CGAffineTransformMakeRotation((self.rotAngle * CGFloat(M_PI)) / 180.0)
})
}
}
Things to notice:
Connect the outlet the the UIImageView
Play with the (1)timer pace, (2)animation pace and (3)rotation angle to get the desired results. This set of variables worked for me.

Creating a Pop animation similar to the presentation of UIAlertView

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.