FTAnimationManager.m 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /*
  2. The MIT License
  3. Copyright (c) 2009 Free Time Studios and Nathan Eror
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in
  11. all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. THE SOFTWARE.
  19. */
  20. #import "FTAnimationManager.h"
  21. #import "FTUtils.h"
  22. #import "FTUtils+NSObject.h"
  23. NSString *const kFTAnimationName = @"kFTAnimationName";
  24. NSString *const kFTAnimationType = @"kFTAnimationType";
  25. NSString *const kFTAnimationTypeIn = @"kFTAnimationTypeIn";
  26. NSString *const kFTAnimationTypeOut = @"kFTAnimationTypeOut";
  27. NSString *const kFTAnimationSlideOut = @"kFTAnimationNameSlideOut";
  28. NSString *const kFTAnimationSlideIn = @"kFTAnimationNameSlideIn";
  29. NSString *const kFTAnimationBackOut = @"kFTAnimationNameBackOut";
  30. NSString *const kFTAnimationBackIn = @"kFTAnimationNameBackIn";
  31. NSString *const kFTAnimationFadeOut = @"kFTAnimationFadeOut";
  32. NSString *const kFTAnimationFadeIn = @"kFTAnimationFadeIn";
  33. NSString *const kFTAnimationFadeBackgroundOut = @"kFTAnimationFadeBackgroundOut";
  34. NSString *const kFTAnimationFadeBackgroundIn = @"kFTAnimationFadeBackgroundIn";
  35. NSString *const kFTAnimationPopIn = @"kFTAnimationPopIn";
  36. NSString *const kFTAnimationPopOut = @"kFTAnimationPopOut";
  37. NSString *const kFTAnimationFallIn = @"kFTAnimationFallIn";
  38. NSString *const kFTAnimationFallOut = @"kFTAnimationFallOut";
  39. NSString *const kFTAnimationFlyOut = @"kFTAnimationFlyOut";
  40. NSString *const kFTAnimationCallerDelegateKey = @"kFTAnimationCallerDelegateKey";
  41. NSString *const kFTAnimationCallerStartSelectorKey = @"kFTAnimationCallerStartSelectorKey";
  42. NSString *const kFTAnimationCallerStopSelectorKey = @"kFTAnimationCallerStopSelectorKey";
  43. NSString *const kFTAnimationTargetViewKey = @"kFTAnimationTargetViewKey";
  44. NSString *const kFTAnimationIsChainedKey = @"kFTAnimationIsChainedKey";
  45. NSString *const kFTAnimationNextAnimationKey = @"kFTAnimationNextAnimationKey";
  46. NSString *const kFTAnimationPrevAnimationKey = @"kFTAnimationPrevAnimationKey";
  47. NSString *const kFTAnimationWasInteractionEnabledKey = @"kFTAnimationWasInteractionEnabledKey";
  48. @interface FTAnimationManager ()
  49. - (CGPoint)overshootPointFor:(CGPoint)point withDirection:(FTAnimationDirection)direction threshold:(CGFloat)threshold;
  50. @end
  51. @implementation FTAnimationManager
  52. @synthesize overshootThreshold = overshootThreshold_;
  53. - (CAAnimationGroup *)delayStartOfAnimation:(CAAnimation *)animation withDelay:(CFTimeInterval)delayTime {
  54. animation.fillMode = kCAFillModeBoth;
  55. animation.beginTime = delayTime;
  56. UIView *targetView = [animation valueForKey:kFTAnimationTargetViewKey];
  57. NSString *name = [animation valueForKey:kFTAnimationName];
  58. NSString *type = [animation valueForKey:kFTAnimationType];
  59. id delegate = [animation valueForKey:kFTAnimationCallerDelegateKey];
  60. NSString *startSelectorString = [animation valueForKey:kFTAnimationCallerStartSelectorKey];
  61. NSString *stopSelectorString = [animation valueForKey:kFTAnimationCallerStopSelectorKey];
  62. SEL startSelector = nil;
  63. SEL stopSelector = nil;
  64. if(startSelectorString != nil) {
  65. startSelector = NSSelectorFromString(startSelectorString);
  66. }
  67. if(stopSelectorString != nil) {
  68. stopSelector = NSSelectorFromString(stopSelectorString);
  69. }
  70. CAAnimationGroup *group = [[FTAnimationManager sharedManager]
  71. animationGroupFor:[NSArray arrayWithObject:animation]
  72. withView:targetView duration:animation.duration + delayTime
  73. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  74. name:name type:type];
  75. return group;
  76. }
  77. - (CAAnimationGroup *)pauseAtEndOfAnimation:(CAAnimation *)animation withDelay:(CFTimeInterval)delayTime {
  78. animation.fillMode = kCAFillModeForwards;
  79. UIView *targetView = [animation valueForKey:kFTAnimationTargetViewKey];
  80. NSString *name = [animation valueForKey:kFTAnimationName];
  81. NSString *type = [animation valueForKey:kFTAnimationType];
  82. id delegate = [animation valueForKey:kFTAnimationCallerDelegateKey];
  83. NSString *startSelectorString = [animation valueForKey:kFTAnimationCallerStartSelectorKey];
  84. NSString *stopSelectorString = [animation valueForKey:kFTAnimationCallerStopSelectorKey];
  85. SEL startSelector = nil;
  86. SEL stopSelector = nil;
  87. if(startSelectorString != nil) {
  88. startSelector = NSSelectorFromString(startSelectorString);
  89. }
  90. if(stopSelectorString != nil) {
  91. stopSelector = NSSelectorFromString(stopSelectorString);
  92. }
  93. CAAnimationGroup *group = [[FTAnimationManager sharedManager]
  94. animationGroupFor:[NSArray arrayWithObject:animation]
  95. withView:targetView duration:animation.duration + delayTime
  96. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  97. name:name type:type];
  98. return group;
  99. }
  100. #pragma mark -
  101. #pragma mark Chained Animations
  102. - (CAAnimation *)chainAnimations:(NSArray *)animations run:(BOOL)run {
  103. CAAnimation *head = nil;
  104. CAAnimation *prev = nil;
  105. for(CAAnimation *anim in animations) {
  106. if(!head) {
  107. head = anim;
  108. } else {
  109. [prev setValue:anim forKey:kFTAnimationNextAnimationKey];
  110. }
  111. [anim setValue:prev forKey:kFTAnimationPrevAnimationKey];
  112. [anim setValue:[NSNumber numberWithBool:YES] forKey:kFTAnimationIsChainedKey];
  113. prev = anim;
  114. }
  115. if(run) {
  116. UIView *target = [head valueForKey:kFTAnimationTargetViewKey];
  117. [target.layer addAnimation:head forKey:[head valueForKey:kFTAnimationName]];
  118. }
  119. return head;
  120. }
  121. #pragma mark -
  122. #pragma mark Utility Methods
  123. - (CAAnimationGroup *)animationGroupFor:(NSArray *)animations withView:(UIView *)view
  124. duration:(NSTimeInterval)duration delegate:(id)delegate
  125. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector
  126. name:(NSString *)name type:(NSString *)type {
  127. CAAnimationGroup *group = [CAAnimationGroup animation];
  128. group.animations = [NSArray arrayWithArray:animations];
  129. group.delegate = self;
  130. group.duration = duration;
  131. group.removedOnCompletion = NO;
  132. if([type isEqualToString:kFTAnimationTypeOut]) {
  133. group.fillMode = kCAFillModeBoth;
  134. }
  135. group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  136. [group setValue:view forKey:kFTAnimationTargetViewKey];
  137. [group setValue:delegate forKey:kFTAnimationCallerDelegateKey];
  138. if(!startSelector) {
  139. startSelector = @selector(animationDidStart:);
  140. }
  141. [group setValue:NSStringFromSelector(startSelector) forKey:kFTAnimationCallerStartSelectorKey];
  142. if(!stopSelector) {
  143. stopSelector = @selector(animationDidStop:finished:);
  144. }
  145. [group setValue:NSStringFromSelector(stopSelector) forKey:kFTAnimationCallerStopSelectorKey];
  146. [group setValue:name forKey:kFTAnimationName];
  147. [group setValue:type forKey:kFTAnimationType];
  148. return group;
  149. }
  150. #pragma mark -
  151. #pragma mark Slide Animation Builders
  152. - (CAAnimation *)slideInAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction
  153. duration:(NSTimeInterval)duration delegate:(id)delegate
  154. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  155. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
  156. animation.fromValue = [NSValue valueWithCGPoint:FTAnimationOffscreenCenterPoint(view.frame, view.center, direction)];
  157. animation.toValue = [NSValue valueWithCGPoint:view.center];
  158. return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration
  159. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  160. name:kFTAnimationSlideIn type:kFTAnimationTypeIn];
  161. }
  162. - (CAAnimation *)slideOutAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction
  163. duration:(NSTimeInterval)duration delegate:(id)delegate
  164. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector{
  165. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
  166. animation.fromValue = [NSValue valueWithCGPoint:view.center];
  167. animation.toValue = [NSValue valueWithCGPoint:FTAnimationOffscreenCenterPoint(view.frame, view.center, direction)];
  168. return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration
  169. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  170. name:kFTAnimationSlideOut type:kFTAnimationTypeOut];
  171. }
  172. #pragma mark -
  173. - (CAAnimation *)slideInAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView
  174. duration:(NSTimeInterval)duration delegate:(id)delegate
  175. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  176. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
  177. animation.fromValue = [NSValue valueWithCGPoint:FTAnimationOutOfViewCenterPoint(enclosingView.bounds, view.frame, view.center, direction)];
  178. animation.toValue = [NSValue valueWithCGPoint:view.center];
  179. return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration
  180. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  181. name:kFTAnimationSlideIn type:kFTAnimationTypeIn];
  182. }
  183. - (CAAnimation *)slideOutAnimationFor:(UIView *)view direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView
  184. duration:(NSTimeInterval)duration delegate:(id)delegate
  185. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector{
  186. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
  187. animation.fromValue = [NSValue valueWithCGPoint:view.center];
  188. animation.toValue = [NSValue valueWithCGPoint:FTAnimationOutOfViewCenterPoint(view.superview.bounds, view.frame, view.center, direction)];
  189. return [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration
  190. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  191. name:kFTAnimationSlideOut type:kFTAnimationTypeOut];
  192. }
  193. #pragma mark -
  194. #pragma mark Bounce Animation Builders
  195. - (CGPoint)overshootPointFor:(CGPoint)point withDirection:(FTAnimationDirection)direction threshold:(CGFloat)threshold {
  196. CGPoint overshootPoint;
  197. if(direction == kFTAnimationTop || direction == kFTAnimationBottom) {
  198. overshootPoint = CGPointMake(point.x, point.y + ((direction == kFTAnimationBottom ? -1 : 1) * threshold));
  199. } else if (direction == kFTAnimationLeft || direction == kFTAnimationRight){
  200. overshootPoint = CGPointMake(point.x + ((direction == kFTAnimationRight ? -1 : 1) * threshold), point.y);
  201. } else if (direction == kFTAnimationTopLeft){
  202. overshootPoint = CGPointMake(point.x + threshold, point.y + threshold);
  203. } else if (direction == kFTAnimationTopRight){
  204. overshootPoint = CGPointMake(point.x - threshold, point.y + threshold);
  205. } else if (direction == kFTAnimationBottomLeft){
  206. overshootPoint = CGPointMake(point.x + threshold, point.y - threshold);
  207. } else if (direction == kFTAnimationBottomRight){
  208. overshootPoint = CGPointMake(point.x - threshold, point.y - threshold);
  209. }
  210. return overshootPoint;
  211. }
  212. - (CAAnimation *)backOutAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction
  213. duration:(NSTimeInterval)duration delegate:(id)delegate
  214. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  215. CGPoint path[3] = {
  216. view.center,
  217. [self overshootPointFor:view.center withDirection:direction threshold:overshootThreshold_],
  218. FTAnimationOffscreenCenterPoint(view.frame, view.center, direction)
  219. };
  220. CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  221. CGMutablePathRef thePath = CGPathCreateMutable();
  222. CGPathAddLines(thePath, NULL, path, 3);
  223. animation.path = thePath;
  224. CGPathRelease(thePath);
  225. NSArray *animations;
  226. if(fade) {
  227. CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:YES];
  228. fade.beginTime = duration * .5f;
  229. fade.fillMode = kCAFillModeForwards;
  230. animations = [NSArray arrayWithObjects:animation, fade, nil];
  231. } else {
  232. animations = [NSArray arrayWithObject:animation];
  233. }
  234. return [self animationGroupFor:animations withView:view duration:duration
  235. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  236. name:kFTAnimationBackOut type:kFTAnimationTypeOut];
  237. }
  238. - (CAAnimation *)backInAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction
  239. duration:(NSTimeInterval)duration delegate:(id)delegate
  240. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  241. CGPoint path[3] = {
  242. FTAnimationOffscreenCenterPoint(view.frame, view.center, direction),
  243. [self overshootPointFor:view.center withDirection:direction threshold:(overshootThreshold_ * 1.15)],
  244. view.center
  245. };
  246. CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  247. CGMutablePathRef thePath = CGPathCreateMutable();
  248. CGPathAddLines(thePath, NULL, path, 3);
  249. animation.path = thePath;
  250. CGPathRelease(thePath);
  251. NSArray *animations;
  252. if(fade) {
  253. CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:NO];
  254. fade.fillMode = kCAFillModeForwards;
  255. animations = [NSArray arrayWithObjects:animation, fade, nil];
  256. } else {
  257. animations = [NSArray arrayWithObject:animation];
  258. }
  259. return [self animationGroupFor:animations withView:view duration:duration
  260. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  261. name:kFTAnimationBackIn type:kFTAnimationTypeIn];
  262. }
  263. #pragma mark -
  264. - (CAAnimation *)backOutAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView
  265. duration:(NSTimeInterval)duration delegate:(id)delegate
  266. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  267. CGPoint path[3] = {
  268. view.center,
  269. [self overshootPointFor:view.center withDirection:direction threshold:overshootThreshold_],
  270. FTAnimationOutOfViewCenterPoint(enclosingView.bounds, view.frame, view.center, direction)
  271. };
  272. CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  273. CGMutablePathRef thePath = CGPathCreateMutable();
  274. CGPathAddLines(thePath, NULL, path, 3);
  275. animation.path = thePath;
  276. CGPathRelease(thePath);
  277. NSArray *animations;
  278. if(fade) {
  279. CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:YES];
  280. fade.beginTime = duration * .5f;
  281. fade.fillMode = kCAFillModeForwards;
  282. animations = [NSArray arrayWithObjects:animation, fade, nil];
  283. } else {
  284. animations = [NSArray arrayWithObject:animation];
  285. }
  286. return [self animationGroupFor:animations withView:view duration:duration
  287. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  288. name:kFTAnimationBackOut type:kFTAnimationTypeOut];
  289. }
  290. - (CAAnimation *)backInAnimationFor:(UIView *)view withFade:(BOOL)fade direction:(FTAnimationDirection)direction inView:(UIView*)enclosingView
  291. duration:(NSTimeInterval)duration delegate:(id)delegate
  292. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  293. CGPoint path[3] = {
  294. FTAnimationOutOfViewCenterPoint(enclosingView.bounds, view.frame, view.center, direction),
  295. [self overshootPointFor:view.center withDirection:direction threshold:(overshootThreshold_ * 1.15)],
  296. view.center
  297. };
  298. CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  299. CGMutablePathRef thePath = CGPathCreateMutable();
  300. CGPathAddLines(thePath, NULL, path, 3);
  301. animation.path = thePath;
  302. CGPathRelease(thePath);
  303. NSArray *animations;
  304. if(fade) {
  305. CAAnimation *fade = [self fadeAnimationFor:view duration:duration * .5f delegate:nil startSelector:nil stopSelector:nil fadeOut:NO];
  306. fade.fillMode = kCAFillModeForwards;
  307. animations = [NSArray arrayWithObjects:animation, fade, nil];
  308. } else {
  309. animations = [NSArray arrayWithObject:animation];
  310. }
  311. return [self animationGroupFor:animations withView:view duration:duration
  312. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  313. name:kFTAnimationBackIn type:kFTAnimationTypeIn];
  314. }
  315. #pragma mark -
  316. #pragma mark Fade Animation Builders
  317. - (CAAnimation *)fadeAnimationFor:(UIView *)view duration:(NSTimeInterval)duration
  318. delegate:(id)delegate startSelector:(SEL)startSelector
  319. stopSelector:(SEL)stopSelector fadeOut:(BOOL)fadeOut {
  320. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
  321. NSString *name, *type;
  322. if(fadeOut) {
  323. animation.fromValue = [NSNumber numberWithFloat:1.f];
  324. animation.toValue = [NSNumber numberWithFloat:0.f];
  325. name = kFTAnimationFadeOut;
  326. type = kFTAnimationTypeOut;
  327. } else {
  328. animation.fromValue = [NSNumber numberWithFloat:0.f];
  329. animation.toValue = [NSNumber numberWithFloat:1.f];
  330. name = kFTAnimationFadeIn;
  331. type = kFTAnimationTypeIn;
  332. }
  333. CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration
  334. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  335. name:name type:type];
  336. group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  337. return group;
  338. }
  339. - (CAAnimation *)fadeBackgroundColorAnimationFor:(UIView *)view duration:(NSTimeInterval)duration
  340. delegate:(id)delegate startSelector:(SEL)startSelector
  341. stopSelector:(SEL)stopSelector fadeOut:(BOOL)fadeOut {
  342. CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
  343. NSString *name, *type;
  344. if(fadeOut) {
  345. animation.fromValue = (id)view.layer.backgroundColor;
  346. animation.toValue = (id)[[UIColor clearColor] CGColor];
  347. name = kFTAnimationFadeBackgroundOut;
  348. type = kFTAnimationTypeOut;
  349. } else {
  350. animation.fromValue = (id)[[UIColor clearColor] CGColor];
  351. animation.toValue = (id)view.layer.backgroundColor;
  352. name = kFTAnimationFadeBackgroundIn;
  353. type = kFTAnimationTypeIn;
  354. }
  355. CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObject:animation] withView:view duration:duration
  356. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  357. name:name type:type];
  358. group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
  359. return group;
  360. }
  361. #pragma mark -
  362. #pragma mark Pop Animation Builders
  363. - (CAAnimation *)popInAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate
  364. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  365. CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
  366. scale.duration = duration;
  367. scale.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:.5f],
  368. [NSNumber numberWithFloat:1.2f],
  369. [NSNumber numberWithFloat:.85f],
  370. [NSNumber numberWithFloat:1.f],
  371. nil];
  372. CABasicAnimation *fadeIn = [CABasicAnimation animationWithKeyPath:@"opacity"];
  373. fadeIn.duration = duration * .4f;
  374. fadeIn.fromValue = [NSNumber numberWithFloat:0.f];
  375. fadeIn.toValue = [NSNumber numberWithFloat:1.f];
  376. fadeIn.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
  377. fadeIn.fillMode = kCAFillModeForwards;
  378. CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:scale, fadeIn, nil] withView:view duration:duration
  379. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  380. name:kFTAnimationPopIn type:kFTAnimationTypeIn];
  381. group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  382. return group;
  383. }
  384. - (CAAnimation *)popOutAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate
  385. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  386. CAKeyframeAnimation *scale = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
  387. scale.duration = duration;
  388. scale.removedOnCompletion = NO;
  389. scale.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:1.f],
  390. [NSNumber numberWithFloat:1.2f],
  391. [NSNumber numberWithFloat:.75f],
  392. nil];
  393. CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"];
  394. fadeOut.duration = duration * .4f;
  395. fadeOut.fromValue = [NSNumber numberWithFloat:1.f];
  396. fadeOut.toValue = [NSNumber numberWithFloat:0.f];
  397. fadeOut.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
  398. fadeOut.beginTime = duration * .6f;
  399. fadeOut.fillMode = kCAFillModeBoth;
  400. return [self animationGroupFor:[NSArray arrayWithObjects:scale, fadeOut, nil] withView:view duration:duration
  401. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  402. name:kFTAnimationPopOut type:kFTAnimationTypeOut];
  403. }
  404. #pragma mark -
  405. #pragma mark Fall In and Fly Out Builders
  406. - (CAAnimation *)fallInAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate
  407. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  408. CABasicAnimation *fall = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
  409. fall.fromValue = [NSNumber numberWithFloat:2.f];
  410. fall.toValue = [NSNumber numberWithFloat:1.f];
  411. fall.duration = duration;
  412. CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"];
  413. fade.fromValue = [NSNumber numberWithFloat:0.f];
  414. fade.toValue = [NSNumber numberWithFloat:1.f];
  415. fade.duration = duration;
  416. CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:fall, fade, nil] withView:view duration:duration
  417. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  418. name:kFTAnimationFallIn type:kFTAnimationTypeIn];
  419. return group;
  420. }
  421. - (CAAnimation *)fallOutAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate
  422. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  423. CABasicAnimation *fall = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
  424. fall.fromValue = [NSNumber numberWithFloat:1.f];
  425. fall.toValue = [NSNumber numberWithFloat:.15f];
  426. fall.duration = duration;
  427. CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"];
  428. fade.fromValue = [NSNumber numberWithFloat:1.f];
  429. fade.toValue = [NSNumber numberWithFloat:0.f];
  430. fade.duration = duration;
  431. CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:fall, fade, nil] withView:view duration:duration
  432. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  433. name:kFTAnimationFallOut type:kFTAnimationTypeOut];
  434. return group;
  435. }
  436. - (CAAnimation *)flyOutAnimationFor:(UIView *)view duration:(NSTimeInterval)duration delegate:(id)delegate
  437. startSelector:(SEL)startSelector stopSelector:(SEL)stopSelector {
  438. CABasicAnimation *fly = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
  439. fly.toValue = [NSNumber numberWithFloat:2.f];
  440. fly.duration = duration;
  441. CABasicAnimation *fade = [CABasicAnimation animationWithKeyPath:@"opacity"];
  442. fade.toValue = [NSNumber numberWithFloat:0.f];
  443. fade.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
  444. CAAnimationGroup *group = [self animationGroupFor:[NSArray arrayWithObjects:fly, fade, nil] withView:view duration:duration
  445. delegate:delegate startSelector:startSelector stopSelector:stopSelector
  446. name:kFTAnimationFlyOut type:kFTAnimationTypeOut];
  447. return group;
  448. }
  449. #pragma mark -
  450. #pragma mark Animation Delegate Methods
  451. - (void)animationDidStart:(CAAnimation *)theAnimation {
  452. UIView *targetView = [theAnimation valueForKey:kFTAnimationTargetViewKey];
  453. [theAnimation setValue:[NSNumber numberWithBool:targetView.userInteractionEnabled] forKey:kFTAnimationWasInteractionEnabledKey];
  454. [targetView setUserInteractionEnabled:NO];
  455. if([[theAnimation valueForKey:kFTAnimationType] isEqualToString:kFTAnimationTypeIn]) {
  456. [targetView setHidden:NO];
  457. }
  458. //Check for chaining and forward the delegate call if necessary
  459. NSObject *callerDelegate = [theAnimation valueForKey:kFTAnimationCallerDelegateKey];
  460. SEL startSelector = NSSelectorFromString([theAnimation valueForKey:kFTAnimationCallerStartSelectorKey]);
  461. FT_CALL_DELEGATE_WITH_ARG(callerDelegate, startSelector, theAnimation)
  462. }
  463. - (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)finished {
  464. UIView *targetView = [theAnimation valueForKey:kFTAnimationTargetViewKey];
  465. BOOL wasInteractionEnabled = [[theAnimation valueForKey:kFTAnimationWasInteractionEnabledKey] boolValue];
  466. [targetView setUserInteractionEnabled:wasInteractionEnabled];
  467. if([[theAnimation valueForKey:kFTAnimationType] isEqualToString:kFTAnimationTypeOut]) {
  468. [targetView setHidden:YES];
  469. }
  470. [targetView.layer removeAnimationForKey:[theAnimation valueForKey:kFTAnimationName]];
  471. //Forward the delegate call
  472. id callerDelegate = [theAnimation valueForKey:kFTAnimationCallerDelegateKey];
  473. SEL stopSelector = NSSelectorFromString([theAnimation valueForKey:kFTAnimationCallerStopSelectorKey]);
  474. if([theAnimation valueForKey:kFTAnimationIsChainedKey]) {
  475. CAAnimation *next = [theAnimation valueForKey:kFTAnimationNextAnimationKey];
  476. if(next) {
  477. //Add the next animation to its layer
  478. UIView *nextTarget = [next valueForKey:kFTAnimationTargetViewKey];
  479. [nextTarget.layer addAnimation:next forKey:[next valueForKey:kFTAnimationName]];
  480. }
  481. }
  482. void *arguments[] = { &theAnimation, &finished };
  483. [callerDelegate performSelectorIfExists:stopSelector withArguments:arguments];
  484. }
  485. #pragma mark Singleton
  486. static FTAnimationManager *sharedAnimationManager = nil;
  487. + (FTAnimationManager *)sharedManager {
  488. @synchronized(self) {
  489. if (sharedAnimationManager == nil) {
  490. sharedAnimationManager = [[self alloc] init];
  491. }
  492. }
  493. return sharedAnimationManager;
  494. }
  495. - (id)init {
  496. self = [super init];
  497. if (self != nil) {
  498. overshootThreshold_ = 10.f;
  499. }
  500. return self;
  501. }
  502. @end
  503. #pragma mark -
  504. @implementation CAAnimation (FTAnimationAdditions)
  505. - (void)setStartSelector:(SEL)selector withTarget:(id)target {
  506. [self setValue:target forKey:kFTAnimationCallerDelegateKey];
  507. [self setValue:NSStringFromSelector(selector) forKey:kFTAnimationCallerStartSelectorKey];
  508. }
  509. - (void)setStopSelector:(SEL)selector withTarget:(id)target {
  510. [self setValue:target forKey:kFTAnimationCallerDelegateKey];
  511. [self setValue:NSStringFromSelector(selector) forKey:kFTAnimationCallerStopSelectorKey];
  512. }
  513. @end