CAKeyframeAnimation
来源:互联网 发布:存放照片的软件 编辑:程序博客网 时间:2024/05/20 15:11
最近很常用 CAKeyframeAnimation 來製作動畫,但有時想找出 animationWithKeyPath 的值卻很困難,所以在這裡歸納一下:transform.scale = 比例轉換transform.scale.x = 闊的比例轉換transform.scale.y = 高的比例轉換transform.rotation.z = 平面圖的旋轉opacity = 透明度
CABasicAnimation animationWithKeyPath Types
When using the ‘CABasicAnimation’ from the QuartzCore Framework in Objective-C, you have to specify an animationWithKeyPath. This is a long string and is not easily listed in the CABasicAnimation, CAPropertyAnimation, or the CAAnimation class. I ended up finding a handy chart within the Core Animation Programming guide in Apple’s iPhone OS Reference Library. Hope this helps save someone time, at least it will for me.
view source
print
?
01.
01.//The following code moves a view up 60 pixels and stops.
02.
03.CABasicAnimation *theAnimation;
04.theAnimation=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
05.theAnimation.delegate = self;
06.theAnimation.duration = 1;
07.theAnimation.repeatCount = 0;
08.theAnimation.removedOnCompletion = FALSE;
09.theAnimation.fillMode = kCAFillModeForwards;
10.theAnimation.autoreverses = NO;
11.theAnimation.fromValue = [NSNumber numberWithFloat:0];
12.theAnimation.toValue = [NSNumber numberWithFloat:-60];
13.
14.[self.view.layer addAnimation:theAnimation forKey:@"animateLayer"];
This entry was posted on Monday, January 25th, 2010 at 2:53 pm and is filed under Objective-C, iPhone. You can follow any comments to this entry through the RSS 2.0 feed. You can leave a comment, or trackbackfrom your own site.
#import "FTAnimationManager.h" #import "FTUtils.h" #import "FTUtils+NSObject.h" NSString *const kFTAnimationName = @"kFTAnimationName"; NSString *const kFTAnimationType = @"kFTAnimationType"; NSString *const kFTAnimationTypeIn = @"kFTAnimationTypeIn"; NSString *const kFTAnimationTypeOut = @"kFTAnimationTypeOut"; NSString *const kFTAnimationSlideOut = @"kFTAnimationNameSlideOut"; NSString *const kFTAnimationSlideIn = @"kFTAnimationNameSlideIn"; NSString *const kFTAnimationBackOut = @"kFTAnimationNameBackOut"; NSString *const kFTAnimationBackIn = @"kFTAnimationNameBackIn"; NSString *const kFTAnimationFadeOut = @"kFTAnimationFadeOut"; NSString *const kFTAnimationFadeIn = @"kFTAnimationFadeIn"; NSString *const kFTAnimationFadeBackgroundOut = @"kFTAnimationFadeBackgroundOut"; NSString *const kFTAnimationFadeBackgroundIn = @"kFTAnimationFadeBackgroundIn"; NSString *const kFTAnimationPopIn = @"kFTAnimationPopIn"; NSString *const kFTAnimationPopOut = @"kFTAnimationPopOut"; NSString *const kFTAnimationFallIn = @"kFTAnimationFallIn"; NSString *const kFTAnimationFallOut = @"kFTAnimationFallOut"; NSString *const kFTAnimationFlyOut = @"kFTAnimationFlyOut"; NSString *const kFTAnimationCallerDelegateKey = @"kFTAnimationCallerDelegateKey"; NSString *const kFTAnimationCallerStartSelectorKey = @"kFTAnimationCallerStartSelectorKey"; NSString *const kFTAnimationCallerStopSelectorKey = @"kFTAnimationCallerStopSelectorKey"; NSString *const kFTAnimationTargetViewKey = @"kFTAnimationTargetViewKey"; NSString *const kFTAnimationIsChainedKey = @"kFTAnimationIsChainedKey"; NSString *const kFTAnimationNextAnimationKey = @"kFTAnimationNextAnimationKey"; NSString *const kFTAnimationPrevAnimationKey = @"kFTAnimationPrevAnimationKey"; NSString *const kFTAnimationWasInteractionEnabledKey = @"kFTAnimationWasInteractionEnabledKey"; @interface FTAnimationManager () - (CGPoint)overshootPointFor:(CGPoint)point withDirection:(FTAnimationDirection)direction threshold:(CGFloat)threshold; @end @implementation FTAnimationManager @synthesize overshootThreshold = overshootThreshold_; - (CAAnimationGroup *)delayStartOfAnimation:(CAAnimation *)animation withDelay:(CFTimeInterval)delayTime { animation.fillMode = kCAFillModeBoth; animation.beginTime = delayTime; UIView *targetView = [animation valueForKey:kFTAnimationTargetViewKey]; NSString *name = [animation valueForKey:kFTAnimationName]; NSString *type = [animation valueForKey:kFTAnimationType]; id delegate = [animation valueForKey:kFTAnimationCallerDelegateKey]; NSString *startSelectorString = [animation valueForKey:kFTAnimationCallerStartSelectorKey]; NSString *stopSelectorString = [animation valueForKey:kFTAnimationCallerStopSelectorKey]; SEL startSelector = nil; SEL stopSelector = nil; if(startSelectorString != nil) { startSelector = NSSelectorFromString(startSelectorString); } if(stopSelectorString != nil) { stopSelector = NSSelectorFromString(stopSelectorString); } CAAnimationGroup *group = [[FTAnimationManager sharedManager] animationGroupFor:[NSArray arrayWithObject:animation] withView:targetView duration:animation.duration + delayTime delegate:delegate startSelector:startSelector stopSelector:stopSelector name:name type:type]; return group; } - (CAAnimationGroup *)pauseAtEndOfAnimation:(CAAnimation *)animation withDelay:(CFTimeInterval)delayTime { animation.fillMode = kCAFillModeForwards; UIView *targetView = [animation valueForKey:kFTAnimationTargetViewKey]; NSString *name = [animation valueForKey:kFTAnimationName]; NSString *type = [animation valueForKey:kFTAnimationType]; id delegate = [animation valueForKey:kFTAnimationCallerDelegateKey]; NSString *startSelectorString = [animation valueForKey:kFTAnimationCallerStartSelectorKey]; NSString *stopSelectorString = [animation valueForKey:kFTAnimationCallerStopSelectorKey]; SEL startSelector = nil; SEL stopSelector = nil; if(startSelectorString != nil) { startSelector = NSSelectorFromString(startSelectorString); } if(stopSelectorString != nil) { stopSelector = NSSelectorFromString(stopSelectorString); } CAAnimationGroup *group = [[FTAnimationManager sharedManager] animationGroupFor:[NSArray arrayWithObject:animation] withView:targetView duration:animation.duration + delayTime delegate:delegate startSelector:startSelector stopSelector:stopSelector name:name type:type]; return group; } #pragma mark - #pragma mark Chained Animations - (CAAnimation *)chainAnimations:(NSArray *)animations run:(BOOL)run { CAAnimation *head = nil; CAAnimation *prev = nil; for(CAAnimation *anim in animations) { if(!head) { head = anim; } else { [prev setValue:anim forKey:kFTAnimationNextAnimationKey]; } [anim setValue:prev forKey:kFTAnimationPrevAnimationKey]; [anim setValue:[NSNumber numberWithBool:YES] forKey:kFTAnimationIsChainedKey]; prev = anim; } if(run) { UIView *target = [head valueForKey:kFTAnimationTargetViewKey]; [target.layer addAnimation:head forKey:[head valueForKey:kFTAnimationName]]; } return head; } #pragma mark - #pragma mark Utility Methods - (CAAnimationGroup *)animationGroupFor:(NSArray *)animations withView:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector name:(NSString *)name type:(NSString *)type { CAAnimationGroup *group = [CAAnimationGroup animation]; group.animations = [NSArray arrayWithArray:animations]; group.delegate = self; group.duration = duration; group.removedOnCompletion = NO; if([type isEqualToString:kFTAnimationTypeOut]) { group.fillMode = kCAFillModeBoth; } group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [group setValue:view forKey:kFTAnimationTargetViewKey]; [group setValue:delegate forKey:kFTAnimationCallerDelegateKey]; if(!startSelector) { startSelector = @selector(animationDidStart:); } [group setValue:NSStringFromSelector(startSelector) forKey:kFTAnimationCallerStartSelectorKey]; if(!stopSelector) { stopSelector = @selector(animationDidStop:finished:); } [group setValue:NSStringFromSelector(stopSelector) forKey:kFTAnimationCallerStopSelectorKey]; [group setValue:name forKey:kFTAnimationName]; [group setValue:type forKey:kFTAnimationType]; return group; } #pragma mark - #pragma mark Slide Animation Builders - (CAAnimation *)slideInAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; animation.fromValue = [NSValue valueWithCGPoint:FTAnimationOffscreenCenterPoint(view.frame, view.center, direction)]; animation.toValue = [NSValue valueWithCGPoint:view.center]; return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationSlideIn type:kFTAnimationTypeIn]; } - (CAAnimation *)slideOutAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector{ CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; animation.fromValue = [NSValue valueWithCGPoint:view.center]; animation.toValue = [NSValue valueWithCGPoint:FTAnimationOffscreenCenterPoint(view.frame, view.center, direction)]; return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationSlideOut type:kFTAnimationTypeOut]; } #pragma mark - - (CAAnimation *)slideInAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; animation.fromValue = [NSValue valueWithCGPoint:FTAnimationOutOfViewCenterPoint(enclosingView.bounds, view.frame, view.center, direction)]; animation.toValue = [NSValue valueWithCGPoint:view.center]; return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationSlideIn type:kFTAnimationTypeIn]; } - (CAAnimation *)slideOutAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector{ CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; animation.fromValue = [NSValue valueWithCGPoint:view.center]; animation.toValue = [NSValue valueWithCGPoint:FTAnimationOutOfViewCenterPoint(view.superview.bounds, view.frame, view.center, direction)]; return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationSlideOut type:kFTAnimationTypeOut]; } #pragma mark - #pragma mark Bounce Animation Builders - (CGPoint)overshootPointFor:(CGPoint)point withDirection:(FTAnimationDirection)direction threshold:(CGFloat)threshold { CGPoint overshootPoint; if(direction == kFTAnimationTop || direction == kFTAnimationBottom) { overshootPoint = CGPointMake(point.x, point.y + ((direction == kFTAnimationBottom ? -1 : 1) * threshold)); } else if (direction == kFTAnimationLeft || direction == kFTAnimationRight){ overshootPoint = CGPointMake(point.x + ((direction == kFTAnimationRight ? -1 : 1) * threshold), point.y); } else if (direction == kFTAnimationTopLeft){ overshootPoint = CGPointMake(point.x + threshold, point.y + threshold); } else if (direction == kFTAnimationTopRight){ overshootPoint = CGPointMake(point.x - threshold, point.y + threshold); } else if (direction == kFTAnimationBottomLeft){ overshootPoint = CGPointMake(point.x + threshold, point.y - threshold); } else if (direction == kFTAnimationBottomRight){ overshootPoint = CGPointMake(point.x - threshold, point.y - threshold); } return overshootPoint; } - (CAAnimation *)backOutAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CGPoint path[3] = { view.center, [self overshootPointFor:view.center withDirection:direction threshold:overshootThreshold_], FTAnimationOffscreenCenterPoint(view.frame, view.center, direction) }; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; CGMutablePathRef thePath = CGPathCreateMutable(); CGPathAddLines(thePath, NULL, path, 3); animation.path = thePath; CGPathRelease(thePath); NSArray *animations; if(fade) { CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:YES]; fade.beginTime = duration * .5f; fade.fillMode = kCAFillModeForwards; animations = [NSArray arrayWithObjects:animation, fade, nil]; } else { animations = [NSArray arrayWithObject:animation]; } return [self animationGroupFor:animations withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationBackOut type:kFTAnimationTypeOut]; } - (CAAnimation *)backInAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CGPoint path[3] = { FTAnimationOffscreenCenterPoint(view.frame, view.center, direction), [self overshootPointFor:view.center withDirection:direction threshold:(overshootThreshold_ * 1.15)], view.center }; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; CGMutablePathRef thePath = CGPathCreateMutable(); CGPathAddLines(thePath, NULL, path, 3); animation.path = thePath; CGPathRelease(thePath); NSArray *animations; if(fade) { CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:NO]; fade.fillMode = kCAFillModeForwards; animations = [NSArray arrayWithObjects:animation, fade, nil]; } else { animations = [NSArray arrayWithObject:animation]; } return [self animationGroupFor:animations withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationBackIn type:kFTAnimationTypeIn]; } #pragma mark - - (CAAnimation *)backOutAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CGPoint path[3] = { view.center, [self overshootPointFor:view.center withDirection:direction threshold:overshootThreshold_], FTAnimationOutOfViewCenterPoint(enclosingView.bounds, view.frame, view.center, direction) }; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; CGMutablePathRef thePath = CGPathCreateMutable(); CGPathAddLines(thePath, NULL, path, 3); animation.path = thePath; CGPathRelease(thePath); NSArray *animations; if(fade) { CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:YES]; fade.beginTime = duration * .5f; fade.fillMode = kCAFillModeForwards; animations = [NSArray arrayWithObjects:animation, fade, nil]; } else { animations = [NSArray arrayWithObject:animation]; } return [self animationGroupFor:animations withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationBackOut type:kFTAnimationTypeOut]; } - (CAAnimation *)backInAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CGPoint path[3] = { FTAnimationOutOfViewCenterPoint(enclosingView.bounds, view.frame, view.center, direction), [self overshootPointFor:view.center withDirection:direction threshold:(overshootThreshold_ * 1.15)], view.center }; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; CGMutablePathRef thePath = CGPathCreateMutable(); CGPathAddLines(thePath, NULL, path, 3); animation.path = thePath; CGPathRelease(thePath); NSArray *animations; if(fade) { CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:NO]; fade.fillMode = kCAFillModeForwards; animations = [NSArray arrayWithObjects:animation, fade, nil]; } else { animations = [NSArray arrayWithObject:animation]; } return [self animationGroupFor:animations withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationBackIn type:kFTAnimationTypeIn]; } #pragma mark - #pragma mark Fade Animation Builders - (CAAnimation *)fadeAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector fadeOut:(BOOL)fadeOut { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; NSString *name, *type; if(fadeOut) { animation.fromValue = [NSNumber numberWithFloat:1.f]; animation.toValue = [NSNumber numberWithFloat:0.f]; name = kFTAnimationFadeOut; type = kFTAnimationTypeOut; } else { animation.fromValue = [NSNumber numberWithFloat:0.f]; animation.toValue = [NSNumber numberWithFloat:1.f]; name = kFTAnimationFadeIn; type = kFTAnimationTypeIn; } CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:name type:type]; group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; return group; } - (CAAnimation *)fadeBackgroundColorAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector fadeOut:(BOOL)fadeOut { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; NSString *name, *type; if(fadeOut) { animation.fromValue = (id)view.layer.backgroundColor; animation.toValue = (id)[[UIColor clearColor] CGColor]; name = kFTAnimationFadeBackgroundOut; type = kFTAnimationTypeOut; } else { animation.fromValue = (id)[[UIColor clearColor] CGColor]; animation.toValue = (id)view.layer.backgroundColor; name = kFTAnimationFadeBackgroundIn; type = kFTAnimationTypeIn; } CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:name type:type]; group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; return group; } #pragma mark - #pragma mark Pop Animation Builders - (CAAnimation *)popInAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; scale.duration = duration; scale.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:.5f], [NSNumber numberWithFloat:1.2f], [NSNumber numberWithFloat:.85f], [NSNumber numberWithFloat:1.f], nil]; CABasicAnimation *fadeIn = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeIn.duration = duration * .4f; fadeIn.fromValue = [NSNumber numberWithFloat:0.f]; fadeIn.toValue = [NSNumber numberWithFloat:1.f]; fadeIn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; fadeIn.fillMode = kCAFillModeForwards; CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:scale, fadeIn, nil] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationPopIn type:kFTAnimationTypeIn]; group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; return group; } - (CAAnimation *)popOutAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; scale.duration = duration; scale.removedOnCompletion = NO; scale.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:1.f], [NSNumber numberWithFloat:1.2f], [NSNumber numberWithFloat:.75f], nil]; CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeOut.duration = duration * .4f; fadeOut.fromValue = [NSNumber numberWithFloat:1.f]; fadeOut.toValue = [NSNumber numberWithFloat:0.f]; fadeOut.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; fadeOut.beginTime = duration * .6f; fadeOut.fillMode = kCAFillModeBoth; return [self animationGroupFor:[NSArray arrayWithObjects:scale, fadeOut, nil] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationPopOut type:kFTAnimationTypeOut]; } #pragma mark - #pragma mark Fall In and Fly Out Builders - (CAAnimation *)fallInAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CABasicAnimation *fall = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; fall.fromValue = [NSNumber numberWithFloat:2.f]; fall.toValue = [NSNumber numberWithFloat:1.f]; fall.duration = duration; CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"]; fade.fromValue = [NSNumber numberWithFloat:0.f]; fade.toValue = [NSNumber numberWithFloat:1.f]; fade.duration = duration; CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:fall, fade, nil] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationFallIn type:kFTAnimationTypeIn]; return group; } - (CAAnimation *)fallOutAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CABasicAnimation *fall = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; fall.fromValue = [NSNumber numberWithFloat:1.f]; fall.toValue = [NSNumber numberWithFloat:.15f]; fall.duration = duration; CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"]; fade.fromValue = [NSNumber numberWithFloat:1.f]; fade.toValue = [NSNumber numberWithFloat:0.f]; fade.duration = duration; CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:fall, fade, nil] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationFallOut type:kFTAnimationTypeOut]; return group; } - (CAAnimation *)flyOutAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CABasicAnimation *fly = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; fly.toValue = [NSNumber numberWithFloat:2.f]; fly.duration = duration; CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"]; fade.toValue = [NSNumber numberWithFloat:0.f]; fade.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:fly, fade, nil] withView:view duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector name:kFTAnimationFlyOut type:kFTAnimationTypeOut]; return group; } #pragma mark - #pragma mark Animation Delegate Methods - (void)animationDidStart:(CAAnimation *)theAnimation { UIView *targetView = [theAnimation valueForKey:kFTAnimationTargetViewKey]; [theAnimation setValue:[NSNumber numberWithBool:targetView.userInteractionEnabled] forKey:kFTAnimationWasInteractionEnabledKey]; [targetView setUserInteractionEnabled:NO]; if([[theAnimation valueForKey:kFTAnimationType] isEqualToString:kFTAnimationTypeIn]) { [targetView setHidden:NO]; } NSObject *callerDelegate = [theAnimation valueForKey:kFTAnimationCallerDelegateKey]; SEL startSelector = NSSelectorFromString([theAnimation valueForKey:kFTAnimationCallerStartSelectorKey]); FT_CALL_DELEGATE_WITH_ARG(callerDelegate, startSelector, theAnimation) } - (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)finished { UIView *targetView = [theAnimation valueForKey:kFTAnimationTargetViewKey]; BOOL wasInteractionEnabled = [[theAnimation valueForKey:kFTAnimationWasInteractionEnabledKey] boolValue]; [targetView setUserInteractionEnabled:wasInteractionEnabled]; if([[theAnimation valueForKey:kFTAnimationType] isEqualToString:kFTAnimationTypeOut]) { [targetView setHidden:YES]; } [targetView.layer removeAnimationForKey:[theAnimation valueForKey:kFTAnimationName]]; id callerDelegate = [theAnimation valueForKey:kFTAnimationCallerDelegateKey]; SEL stopSelector = NSSelectorFromString([theAnimation valueForKey:kFTAnimationCallerStopSelectorKey]); if([theAnimation valueForKey:kFTAnimationIsChainedKey]) { CAAnimation *next = [theAnimation valueForKey:kFTAnimationNextAnimationKey]; if(next) { UIView *nextTarget = [next valueForKey:kFTAnimationTargetViewKey]; [nextTarget.layer addAnimation:next forKey:[next valueForKey:kFTAnimationName]]; } } void *arguments[] = { &theAnimation, &finished }; [callerDelegate performSelectorIfExists:stopSelector withArguments:arguments]; } #pragma mark Singleton static FTAnimationManager *sharedAnimationManager = nil; + (FTAnimationManager *)sharedManager { @synchronized(self) { if (sharedAnimationManager == nil) { sharedAnimationManager = [[self alloc] init]; } } return sharedAnimationManager; } - (id)init { self = [super init]; if (self != nil) { overshootThreshold_ = 10.f; } return self; } @end #pragma mark - @implementation CAAnimation (FTAnimationAdditions) - (void)setStartSelector:(SEL)selector withTarget:(id)target { [self setValue:target forKey:kFTAnimationCallerDelegateKey]; [self setValue:NSStringFromSelector(selector) forKey:kFTAnimationCallerStartSelectorKey]; } - (void)setStopSelector:(SEL)selector withTarget:(id)target { [self setValue:target forKey:kFTAnimationCallerDelegateKey]; [self setValue:NSStringFromSelector(selector) forKey:kFTAnimationCallerStopSelectorKey]; } @end #import "FTAnimation+UIView.h" #import "FTUtils.h" #import "FTUtils+NSObject.h" @implementation UIView (FTAnimationAdditions) #pragma mark - Sliding Animations - (void)slideInFrom:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *slideInAnim = [[FTAnimationManager sharedManager] slideInAnimationFor:self direction:direction duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:slideInAnim forKey:kFTAnimationSlideIn]; } - (void)slideInFrom:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate { [self slideInFrom:direction duration:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)slideOutTo:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *slideOutAnim = [[FTAnimationManager sharedManager] slideOutAnimationFor:self direction:direction duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:slideOutAnim forKey:kFTAnimationSlideOut]; } - (void)slideOutTo:(FTAnimationDirection)direction duration:(NSTimeInterval)duration delegate:(id)delegate { [self slideOutTo:direction duration:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)slideInFrom:(FTAnimationDirection)direction inView:(UIView*)enclosingView duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *slideInAnim = [[FTAnimationManager sharedManager] slideInAnimationFor:self direction:direction inView:(UIView*)enclosingView duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:slideInAnim forKey:kFTAnimationSlideIn]; } - (void)slideOutTo:(FTAnimationDirection)direction inView:(UIView*)enclosingView duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *slideOutAnim = [[FTAnimationManager sharedManager] slideOutAnimationFor:self direction:direction inView:(UIView*)enclosingView duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:slideOutAnim forKey:kFTAnimationSlideOut]; } #pragma mark - Back In/Out Animations - (void)backOutTo:(FTAnimationDirection)direction withFade:(BOOL)fade duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *backOutAnim = [[FTAnimationManager sharedManager] backOutAnimationFor:self withFade:fade direction:direction duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:backOutAnim forKey:kFTAnimationBackOut]; } - (void)backOutTo:(FTAnimationDirection)direction withFade:(BOOL)fade duration:(NSTimeInterval)duration delegate:(id)delegate { [self backOutTo:direction withFade:fade duration:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)backInFrom:(FTAnimationDirection)direction withFade:(BOOL)fade duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *backInAnim = [[FTAnimationManager sharedManager] backInAnimationFor:self withFade:fade direction:direction duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:backInAnim forKey:kFTAnimationBackIn]; } - (void)backInFrom:(FTAnimationDirection)direction withFade:(BOOL)fade duration:(NSTimeInterval)duration delegate:(id)delegate { [self backInFrom:direction withFade:fade duration:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)backOutTo:(FTAnimationDirection)direction inView:(UIView*)enclosingView withFade:(BOOL)fade duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *backOutAnim = [[FTAnimationManager sharedManager] backOutAnimationFor:self withFade:fade direction:direction inView:enclosingView duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:backOutAnim forKey:kFTAnimationBackOut]; } - (void)backInFrom:(FTAnimationDirection)direction inView:(UIView*)enclosingView withFade:(BOOL)fade duration:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *backInAnim = [[FTAnimationManager sharedManager] backInAnimationFor:self withFade:fade direction:direction inView:enclosingView duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:backInAnim forKey:kFTAnimationBackIn]; } #pragma mark - Fade Animations - (void)fadeIn:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] fadeAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector fadeOut:NO]; [self.layer addAnimation:anim forKey:kFTAnimationFadeIn]; } - (void)fadeIn:(NSTimeInterval)duration delegate:(id)delegate { [self fadeIn:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)fadeOut:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] fadeAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector fadeOut:YES]; [self.layer addAnimation:anim forKey:kFTAnimationFadeOut]; } - (void)fadeOut:(NSTimeInterval)duration delegate:(id)delegate { [self fadeOut:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)fadeBackgroundColorIn:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] fadeBackgroundColorAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector fadeOut:NO]; [self.layer addAnimation:anim forKey:kFTAnimationFadeBackgroundIn]; } - (void)fadeBackgroundColorIn:(NSTimeInterval)duration delegate:(id)delegate { [self fadeBackgroundColorIn:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)fadeBackgroundColorOut:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] fadeBackgroundColorAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector fadeOut:YES]; [self.layer addAnimation:anim forKey:kFTAnimationFadeBackgroundOut]; } - (void)fadeBackgroundColorOut:(NSTimeInterval)duration delegate:(id)delegate { [self fadeBackgroundColorOut:duration delegate:delegate startSelector:nil stopSelector:nil]; } #pragma mark - Popping Animations - (void)popIn:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] popInAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:anim forKey:kFTAnimationPopIn]; } - (void)popIn:(NSTimeInterval)duration delegate:(id)delegate { [self popIn:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)popOut:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] popOutAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:anim forKey:kFTAnimationPopOut]; } - (void)popOut:(NSTimeInterval)duration delegate:(id)delegate { [self popOut:duration delegate:delegate startSelector:nil stopSelector:nil]; } #pragma mark - Fall In and Fly Out - (void)fallIn:(NSTimeInterval)duration delegate:(id)delegate { [self fallIn:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)fallIn:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] fallInAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:anim forKey:kFTAnimationFallIn]; } - (void)fallOut:(NSTimeInterval)duration delegate:(id)delegate { [self fallOut:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)fallOut:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] fallOutAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:anim forKey:kFTAnimationFallOut]; } - (void)flyOut:(NSTimeInterval)duration delegate:(id)delegate { [self flyOut:duration delegate:delegate startSelector:nil stopSelector:nil]; } - (void)flyOut:(NSTimeInterval)duration delegate:(id)delegate startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector { CAAnimation *anim = [[FTAnimationManager sharedManager] flyOutAnimationFor:self duration:duration delegate:delegate startSelector:startSelector stopSelector:stopSelector]; [self.layer addAnimation:anim forKey:kFTAnimationFlyOut]; } @end #import "FTUtils+NSObject.h" @implementation NSObject (FTUtilsAdditions) - (void)performSelector:(SEL)selector andReturnTo:(void *)returnData withArguments:(void **)arguments { NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setSelector:selector]; NSUInteger argCount = [methodSignature numberOfArguments]; for (int i=2; i < argCount; i++) { void *arg = arguments[i-2]; [invocation setArgument:arg atIndex:i]; } [invocation invokeWithTarget:self]; if(returnData != NULL) { [invocation getReturnValue:returnData]; } } - (void)performSelector:(SEL)selector withArguments:(void **)arguments { [self performSelector:selector andReturnTo:NULL withArguments:arguments]; } - (void)performSelectorIfExists:(SEL)selector andReturnTo:(void *)returnData withArguments:(void **)arguments { if([self respondsToSelector:selector]) { [self performSelector:selector andReturnTo:returnData withArguments:arguments]; } } - (void)performSelectorIfExists:(SEL)selector withArguments:(void **)arguments { [self performSelectorIfExists:selector andReturnTo:NULL withArguments:arguments]; } @end @implementation NSArray (FTUtilsAdditions) - (NSArray *)reversedArray { NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self count]]; NSEnumerator *enumerator = [self reverseObjectEnumerator]; for (id element in enumerator) { [array addObject:element]; } return [NSArray arrayWithArray:array]; } @end @implementation NSMutableArray (FTUtilsAdditions) - (void)reverse { NSUInteger i = 0; NSUInteger j = [self count] - 1; while (i < j) { [self exchangeObjectAtIndex:i withObjectAtIndex:j]; i++; j--; } } @end #if NS_BLOCKS_AVAILABLE #import "FTUtils+UIGestureRecognizer.h" #import <objc/runtime.h> @interface UIGestureRecognizer() - (void)handleAction:(UIGestureRecognizer *)recognizer; @end static char * kFTGestureActionKey = "ft_gestureAction"; static char * kFTGestureDisabledKey = "ft_gestureDisabled"; @implementation UIGestureRecognizer(FTBlockAdditions) + (id)recognizer { return [self recognizerWithActionBlock:nil]; } + (id)recognizerWithActionBlock:(FTGestureActionBlock)action { id me = [[self class] alloc]; me = [me initWithTarget:me action:@selector(handleAction:)]; [me setActionBlock:action]; return [me autorelease]; } - (void)handleAction:(UIGestureRecognizer *)recognizer { if(self.actionBlock && !self.disabled) { self.actionBlock(recognizer); } } - (FTGestureActionBlock)actionBlock { return objc_getAssociatedObject(self, kFTGestureActionKey); } - (void)setActionBlock:(FTGestureActionBlock)actionBlock { objc_setAssociatedObject(self, kFTGestureActionKey, actionBlock, OBJC_ASSOCIATION_COPY); } - (BOOL)disabled { return [objc_getAssociatedObject(self, kFTGestureDisabledKey) boolValue]; } - (void)setDisabled:(BOOL)disabled { objc_setAssociatedObject(self, kFTGestureDisabledKey, [NSNumber numberWithBool:disabled], OBJC_ASSOCIATION_RETAIN); } @end #endif #import "BackInOut.h" #import "FTAnimation.h" @implementation BackInOut + (NSString *)displayName { return @"Back In/Back Out"; } - (void)viewDidLoad { self.hasDirectionControl = YES; } - (void)performAnimation:(id)sender { if(self.viewToAnimate.hidden) { [self.viewToAnimate backInFrom:self.directionControl.selectedSegmentIndex inView:self.viewToAnimate.superview withFade:NO duration:0.4 delegate:nil startSelector:nil stopSelector:nil]; } else { [self.viewToAnimate backOutTo:self.directionControl.selectedSegmentIndex inView:self.viewToAnimate.superview withFade:NO duration:0.4 delegate:nil startSelector:nil stopSelector:nil]; } } @end #import "PopInOut.h" #import "FTAnimation.h" @implementation PopInOut + (NSString *)displayName { return @"Pop In/Pop Out"; } - (void)performAnimation:(id)sender { if(self.viewToAnimate.hidden) { [self.viewToAnimate popIn:.4 delegate:nil]; } else { [self.viewToAnimate popOut:.4 delegate:nil]; } } @end #import "FlyOut.h" #import "FTAnimation.h" @implementation FlyOut + (NSString *)displayName { return @"Fly Out"; } - (void)performAnimation:(id)sender { if(self.viewToAnimate.hidden) { [self.viewToAnimate fadeIn:.2 delegate:nil]; } else { [self.viewToAnimate flyOut:.4 delegate:nil]; } }