Skip to content

Instantly share code, notes, and snippets.

@r3econ
Created April 22, 2014 20:27
Show Gist options
  • Save r3econ/11193115 to your computer and use it in GitHub Desktop.
Save r3econ/11193115 to your computer and use it in GitHub Desktop.
UIView Animation Extensions
//
// Created by Rafal Sroka
//
// License CC0.
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any means.
//
/**
@brief Direction of flip animation.
*/
typedef NS_ENUM(NSUInteger, UIViewAnimationFlipDirection)
{
UIViewAnimationFlipDirectionFromTop,
UIViewAnimationFlipDirectionFromLeft,
UIViewAnimationFlipDirectionFromRight,
UIViewAnimationFlipDirectionFromBottom,
};
/**
@brief Direction of rotation animation.
*/
typedef NS_ENUM(NSUInteger, UIViewAnimationRotationDirection)
{
UIViewAnimationRotationDirectionRight,
UIViewAnimationRotationDirectionLeft
};
@interface UIView (AnimationExtensions)
/**
@brief Shakes the view horizontally for a short period of time.
*/
- (void)shakeHorizontally;
/**
@brief Shakes the view vertically for a short period of time.
*/
- (void)shakeVertically;
/**
@brief Adds a motion effect to the view. Similar effect can be seen in the
background of the Home Screen on iOS 7.
@note Motion effects are available starting from iOS 7. Calling this method on
older iOS will be ignored.
*/
- (void)applyMotionEffects;
/**
@brief Performs a pulsing scale animation on a view.
@param duration - duration of the animation
@param repeat - pass YES for the animation to repeat.
*/
- (void)pulseToSize:(CGFloat)scale
duration:(NSTimeInterval)duration
repeat:(BOOL)repeat;
/**
@brief Performs a 3D-like flip animation of the view around center X or Y axis.
@param duration - total time of the animation.
@param direction - direction of the flip movement.
@param repeatCount - number of repetitions of the animation. Pass HUGE_VALF to repeat forever.
@param shouldAutoreverse - pass YES to make the animation reverse when it reaches the end.
*/
- (void)flipWithDuration:(NSTimeInterval)duration
direction:(UIViewAnimationFlipDirection)direction
repeatCount:(NSUInteger)repeatCount
autoreverse:(BOOL)shouldAutoreverse;
/**
@brief Performs a rotation animation of the view around its anchor point.
@param angle - end angle of the rotation. Pass M_PI * 2.0 for full circle rotation.
@param duration - total time of the animation.
@param direction - left or right direction of the rotation.
@param repeatCount - number of repetitions of the animation. Pass HUGE_VALF to repeat forever.
@param shouldAutoreverse - pass YES to make the animation reverse when it reaches the end.
*/
- (void)rotateToAngle:(CGFloat)angle
duration:(NSTimeInterval)duration
direction:(UIViewAnimationRotationDirection)direction
repeatCount:(NSUInteger)repeatCount
autoreverse:(BOOL)shouldAutoreverse;
/**
@brief Stops current animations.
*/
- (void)stopAnimation;
/**
@brief Checks if the view is being animated.
*/
- (BOOL)isBeingAnimated;
@end
//
// Created by Rafal Sroka
//
// License CC0.
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any means.
//
#import "UIView+AnimationExtensions.h"
@implementation UIView (AnimationExtensions)
- (void)shakeHorizontally
{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.duration = 0.5;
animation.values = @[@(-12), @(12), @(-8), @(8), @(-4), @(4), @(0) ];
[self.layer addAnimation:animation forKey:@"shake"];
}
- (void)shakeVertically
{
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
animation.duration = 0.5;
animation.values = @[@(-12), @(12), @(-8), @(8), @(-4), @(4), @(0) ];
[self.layer addAnimation:animation forKey:@"shake"];
}
- (void)applyMotionEffects
{
// Motion effects are available starting from iOS 7.
if (([[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending))
{
UIInterpolatingMotionEffect *horizontalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x"
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
horizontalEffect.minimumRelativeValue = @(-10.0f);
horizontalEffect.maximumRelativeValue = @( 10.0f);
UIInterpolatingMotionEffect *verticalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y"
type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
verticalEffect.minimumRelativeValue = @(-10.0f);
verticalEffect.maximumRelativeValue = @( 10.0f);
UIMotionEffectGroup *motionEffectGroup = [[UIMotionEffectGroup alloc] init];
motionEffectGroup.motionEffects = @[horizontalEffect, verticalEffect];
[self addMotionEffect:motionEffectGroup];
}
}
- (void)pulseToSize:(CGFloat)scale
duration:(NSTimeInterval)duration
repeat:(BOOL)repeat
{
CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
pulseAnimation.duration = duration;
pulseAnimation.toValue = [NSNumber numberWithFloat:scale];
pulseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
pulseAnimation.autoreverses = YES;
pulseAnimation.repeatCount = repeat ? HUGE_VALF : 0;
[self.layer addAnimation:pulseAnimation
forKey:@"pulse"];
}
- (void)flipWithDuration:(NSTimeInterval)duration
direction:(UIViewAnimationFlipDirection)direction
repeatCount:(NSUInteger)repeatCount
autoreverse:(BOOL)shouldAutoreverse
{
NSString *subtype = nil;
switch (direction)
{
case UIViewAnimationFlipDirectionFromTop:
subtype = @"fromTop";
break;
case UIViewAnimationFlipDirectionFromLeft:
subtype = @"fromLeft";
break;
case UIViewAnimationFlipDirectionFromBottom:
subtype = @"fromBottom";
break;
case UIViewAnimationFlipDirectionFromRight:
default:
subtype = @"fromRight";
break;
}
CATransition *transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = @"flip";
transition.subtype = subtype;
transition.duration = duration;
transition.repeatCount = repeatCount;
transition.autoreverses = shouldAutoreverse;
[self.layer addAnimation:transition
forKey:@"spin"];
}
- (void)rotateToAngle:(CGFloat)angle
duration:(NSTimeInterval)duration
direction:(UIViewAnimationRotationDirection)direction
repeatCount:(NSUInteger)repeatCount
autoreverse:(BOOL)shouldAutoreverse;
{
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = @(direction == UIViewAnimationRotationDirectionRight ? angle : -angle);
rotationAnimation.duration = duration;
rotationAnimation.autoreverses = shouldAutoreverse;
rotationAnimation.repeatCount = repeatCount;
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.layer addAnimation:rotationAnimation
forKey:@"transform.rotation.z"];
}
- (void)stopAnimation
{
[CATransaction begin];
[self.layer removeAllAnimations];
[CATransaction commit];
[CATransaction flush];
}
- (BOOL)isBeingAnimated
{
return [self.layer.animationKeys count];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment