├── .gitignore ├── LICENSE ├── POP+MCAnimate.podspec ├── POP+MCAnimate ├── Animations │ ├── MCAnimationProxy.h │ ├── MCAnimationProxy.m │ ├── MCBasicAnimation.h │ ├── MCBasicAnimation.m │ ├── MCBeginTime.h │ ├── MCBeginTime.m │ ├── MCDecayAnimation.h │ ├── MCDecayAnimation.m │ ├── MCSpringAnimation.h │ ├── MCSpringAnimation.m │ ├── MCStopProxy.h │ ├── MCStopProxy.m │ ├── NSArray+MCSequence.h │ └── NSArray+MCSequence.m ├── Group │ ├── MCAnimationGroup.h │ ├── MCAnimationGroup.m │ ├── MCAnimationGroupInternal.h │ └── MCAnimationGroupInternal.m ├── Internal │ ├── MCProxy.h │ ├── MCProxy.m │ ├── NSNumber+MCAdditions.h │ └── NSNumber+MCAdditions.m ├── POP+MCAnimate.h ├── Shorthand │ ├── CALayer+MCShorthand.h │ ├── CALayer+MCShorthand.m │ ├── MCShorthand.h │ ├── UIView+MCShorthand.h │ └── UIView+MCShorthand.m └── Velocity │ ├── MCVelocityProxy.h │ ├── MCVelocityProxy.m │ └── MCVelocityProxyInternal.h ├── POP-Demo ├── POP-Demo.xcodeproj │ └── project.pbxproj ├── POP-Demo │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── MCAppDelegate.h │ ├── MCAppDelegate.m │ ├── MCSequenceController.h │ ├── MCSequenceController.m │ ├── MCViewController.h │ ├── MCViewController.m │ ├── POP-Demo-Info.plist │ ├── POP-Demo-Prefix.pch │ ├── POPCGUtils.h │ ├── POPCGUtils.mm │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── POP-DemoTests │ ├── POP-DemoTests-Info.plist │ ├── POP_DemoTests.m │ └── en.lproj │ │ └── InfoPlist.strings └── Podfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | .DS_Store 6 | build/ 7 | *.pbxuser 8 | !default.pbxuser 9 | *.mode1v3 10 | !default.mode1v3 11 | *.mode2v3 12 | !default.mode2v3 13 | *.perspectivev3 14 | !default.perspectivev3 15 | *.xcworkspace 16 | !default.xcworkspace 17 | xcuserdata 18 | profile 19 | *.moved-aside 20 | DerivedData 21 | .idea/ 22 | 23 | # CocoaPods 24 | Pods 25 | Podfile.lock 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Matthew Cheok 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /POP+MCAnimate.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'POP+MCAnimate' 3 | s.version = '2.0.1' 4 | s.platform = :ios, '7.0' 5 | s.license = { :type => 'MIT', :file => 'LICENSE' } 6 | s.summary = 'Concise syntax for the Pop animation framework.' 7 | s.homepage = 'https://github.com/matthewcheok/POP-MCAnimate' 8 | s.author = { 'Matthew Cheok' => 'cheok.jz@gmail.com' } 9 | s.requires_arc = true 10 | s.source = { 11 | :git => 'https://github.com/matthewcheok/POP-MCAnimate.git', 12 | :branch => 'master', 13 | :tag => s.version.to_s 14 | } 15 | s.source_files = 'POP+MCAnimate/*.{h,m}' 16 | s.public_header_files = 'POP+MCAnimate/*.h' 17 | 18 | s.dependency 'pop', '~> 1.0' 19 | 20 | s.subspec 'Internal' do |ss| 21 | ss.source_files = 'POP+MCAnimate/Internal/*.{h,m}' 22 | ss.public_header_files = '' 23 | end 24 | 25 | s.subspec 'Velocity' do |ss| 26 | ss.dependency 'POP+MCAnimate/Internal' 27 | ss.source_files = 'POP+MCAnimate/Velocity/*.{h,m}' 28 | end 29 | 30 | s.subspec 'Group' do |ss| 31 | ss.source_files = 'POP+MCAnimate/Group/*.{h,m}' 32 | end 33 | 34 | s.subspec 'Animations' do |ss| 35 | ss.dependency 'POP+MCAnimate/Internal' 36 | ss.dependency 'POP+MCAnimate/Velocity' 37 | ss.dependency 'POP+MCAnimate/Group' 38 | ss.dependency 'POP+MCAnimate/Shorthand' 39 | ss.source_files = 'POP+MCAnimate/Animations/*.{h,m}' 40 | end 41 | 42 | s.subspec 'Shorthand' do |ss| 43 | ss.source_files = 'POP+MCAnimate/Shorthand/*.{h,m}' 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCAnimationProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCAnimationProxy.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 29/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCProxy.h" 10 | #import "MCVelocityProxy.h" 11 | #import "MCBeginTime.h" 12 | 13 | #import 14 | 15 | @interface MCAnimationProxy : MCProxy 16 | 17 | @property (weak, nonatomic) id delegate; 18 | 19 | // subclasses should implement the following methods 20 | 21 | + (NSString *)propertyNameForSelector:(SEL)selector; 22 | - (POPPropertyAnimation *)propertyAnimation; 23 | 24 | @end 25 | 26 | @interface NSObject (MCAnimationProxy) 27 | 28 | @property (weak, nonatomic) id pop_delegate; 29 | 30 | + (void)pop_addAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id obj, CGFloat values[]))readBlock writeBlock:(void (^)(id obj, const CGFloat values[]))writeBlock threshold:(CGFloat)threshold __attribute__((deprecated)); 31 | + (void)pop_registerAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id obj, CGFloat values[]))readBlock writeBlock:(void (^)(id obj, const CGFloat values[]))writeBlock threshold:(CGFloat)threshold; 32 | 33 | @end 34 | 35 | #ifdef MCANIMATE_SHORTHAND 36 | 37 | @interface NSObject (MCAnimationProxy_DropPrefix) 38 | 39 | + (void)addAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id obj, CGFloat values[]))readBlock writeBlock:(void (^)(id obj, const CGFloat values[]))writeBlock threshold:(CGFloat)threshold __attribute__((deprecated)); 40 | + (void)registerAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id obj, CGFloat values[]))readBlock writeBlock:(void (^)(id obj, const CGFloat values[]))writeBlock threshold:(CGFloat)threshold; 41 | 42 | @end 43 | 44 | @implementation NSObject (MCAnimationProxy_DropPrefix) 45 | 46 | + (void)addAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id obj, CGFloat values[]))readBlock writeBlock:(void (^)(id obj, const CGFloat values[]))writeBlock threshold:(CGFloat)threshold { 47 | [self pop_registerAnimatablePropertyWithName:propertyName readBlock:readBlock writeBlock:writeBlock threshold:threshold]; 48 | } 49 | 50 | + (void)registerAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id obj, CGFloat values[]))readBlock writeBlock:(void (^)(id obj, const CGFloat values[]))writeBlock threshold:(CGFloat)threshold { 51 | [self pop_registerAnimatablePropertyWithName:propertyName readBlock:readBlock writeBlock:writeBlock threshold:threshold]; 52 | } 53 | 54 | @end 55 | 56 | #endif -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCAnimationProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCAnimationProxy.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 29/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAnimationProxy.h" 10 | #import "MCAnimationGroupInternal.h" 11 | 12 | #import 13 | 14 | static char kAnimationDelegateKey; 15 | 16 | @implementation MCAnimationProxy 17 | 18 | #pragma mark - Methods 19 | 20 | + (NSString *)propertyNameForSelector:(SEL)selector { 21 | [NSException raise:NSInternalInconsistencyException format:@"Use a concrete subclass of MCAnimationProxy."]; 22 | return nil; 23 | } 24 | 25 | - (POPPropertyAnimation *)propertyAnimation { 26 | [NSException raise:NSInternalInconsistencyException format:@"Use a concrete subclass of MCAnimationProxy."]; 27 | return nil; 28 | } 29 | 30 | #pragma mark - Methods 31 | 32 | - (void)completeInvocationWithPropertyName:(NSString *)propertyName andValue:(id)value { 33 | if ([propertyName hasPrefix:@"pop_"]) { 34 | propertyName = [propertyName substringFromIndex:4]; 35 | } 36 | 37 | // setup property 38 | POPAnimatableProperty *property = [self __animatablePropertyForPropertyName:propertyName]; 39 | if (!property) { 40 | [NSException raise:NSInternalInconsistencyException format:@"Property '%@' is not animatable.", propertyName]; 41 | } 42 | 43 | // setup animation 44 | POPPropertyAnimation *animation = [self.object pop_animationForKey:propertyName]; 45 | 46 | if (!animation) { 47 | animation = [self propertyAnimation]; 48 | animation.property = property; 49 | } 50 | 51 | if (value) { 52 | animation.toValue = value; 53 | } 54 | 55 | MCAnimationGroup *group = [NSObject mc_activeAnimationGroup]; 56 | if (group) { 57 | [group addAnimation:animation]; 58 | } 59 | 60 | [self.object pop_addAnimation:animation forKey:propertyName]; 61 | } 62 | 63 | #pragma mark - Private 64 | 65 | + (NSMutableDictionary *)__animatablePropertiesByClassName { 66 | static NSMutableDictionary *__propertiesByClassName = nil; 67 | if (!__propertiesByClassName) { 68 | NSDictionary *mapping = @{ 69 | @"CALayer": @{ 70 | @"backgroundColor": kPOPLayerBackgroundColor, 71 | @"bounds": kPOPLayerBounds, 72 | @"opacity": kPOPLayerOpacity, 73 | @"position": kPOPLayerPosition, 74 | @"zPosition": kPOPLayerZPosition, 75 | 76 | @"positionX": kPOPLayerPositionX, 77 | @"positionY": kPOPLayerPositionY, 78 | @"rotation": kPOPLayerRotation, 79 | @"rotationX": kPOPLayerRotationX, 80 | @"rotationY": kPOPLayerRotationY, 81 | @"scaleX": kPOPLayerScaleX, 82 | @"scaleY": kPOPLayerScaleY, 83 | @"scaleXY": kPOPLayerScaleXY, 84 | @"translationX": kPOPLayerTranslationX, 85 | @"translationXY": kPOPLayerTranslationXY, 86 | @"translationY": kPOPLayerTranslationY, 87 | @"translationZ": kPOPLayerTranslationZ, 88 | @"size": kPOPLayerSize, 89 | }, 90 | 91 | @"CAShapeLayer": @{ 92 | @"strokeColor": kPOPShapeLayerStrokeColor, 93 | @"strokeStart": kPOPShapeLayerStrokeStart, 94 | @"strokeEnd": kPOPShapeLayerStrokeEnd 95 | }, 96 | 97 | @"NSLayoutConstraint": @{ 98 | @"constant": kPOPLayoutConstraintConstant 99 | }, 100 | 101 | @"UIView": @{ 102 | @"alpha": kPOPViewAlpha, 103 | @"backgroundColor": kPOPViewBackgroundColor, 104 | @"bounds": kPOPViewBounds, 105 | @"center": kPOPViewCenter, 106 | @"frame": kPOPViewFrame, 107 | @"scaleX": kPOPViewScaleX, 108 | @"scaleY": kPOPViewScaleY, 109 | @"scaleXY": kPOPViewScaleXY, 110 | }, 111 | 112 | @"UIScrollView": @{ 113 | @"contentOffset": kPOPScrollViewContentOffset, 114 | @"contentSize": kPOPScrollViewContentSize 115 | }, 116 | 117 | @"UINavigationBar": @{ 118 | @"barTintColor": kPOPNavigationBarBarTintColor 119 | }, 120 | 121 | @"UIToolbar": @{ 122 | @"barTintColor": kPOPNavigationBarBarTintColor 123 | }, 124 | 125 | @"UITabBar": @{ 126 | @"barTintColor": kPOPTabBarBarTintColor 127 | }, 128 | }; 129 | 130 | __propertiesByClassName = [NSMutableDictionary dictionary]; 131 | for (NSString *className in mapping) { 132 | __propertiesByClassName[className] = [mapping[className] mutableCopy]; 133 | } 134 | } 135 | 136 | return __propertiesByClassName; 137 | } 138 | 139 | - (POPAnimatableProperty *)__animatablePropertyForPropertyName:(NSString *)propertyName { 140 | NSDictionary *animatableProperties = [[self class] __animatablePropertiesByClassName]; 141 | 142 | Class class = [self.object class]; 143 | 144 | while (class != [NSObject class]) { 145 | NSString *className = NSStringFromClass(class); 146 | NSDictionary *classProperties = [animatableProperties objectForKey:className]; 147 | if (classProperties) { 148 | id property = [classProperties objectForKey:propertyName]; 149 | if ([property isKindOfClass:[NSString class]]) { 150 | return [POPAnimatableProperty propertyWithName:property]; 151 | } 152 | else if ([property isKindOfClass:[POPAnimatableProperty class]]) { 153 | return property; 154 | } 155 | } 156 | 157 | class = [class superclass]; 158 | } 159 | 160 | return nil; 161 | } 162 | 163 | @end 164 | 165 | @implementation NSObject (MCAnimationProxy) 166 | 167 | - (id)pop_delegate { 168 | return objc_getAssociatedObject(self, &kAnimationDelegateKey); 169 | } 170 | 171 | - (void)setPop_delegate:(id)pop_delegate { 172 | objc_setAssociatedObject(self, &kAnimationDelegateKey, pop_delegate, OBJC_ASSOCIATION_ASSIGN); 173 | } 174 | 175 | + (void)pop_addAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id, CGFloat *))readBlock writeBlock:(void (^)(id, const CGFloat *))writeBlock threshold:(CGFloat)threshold { 176 | [self pop_registerAnimatablePropertyWithName:propertyName readBlock:readBlock writeBlock:writeBlock threshold:threshold]; 177 | } 178 | 179 | + (void)pop_registerAnimatablePropertyWithName:(NSString *)propertyName readBlock:(void (^)(id, CGFloat *))readBlock writeBlock:(void (^)(id, const CGFloat *))writeBlock threshold:(CGFloat)threshold { 180 | NSString *className = NSStringFromClass(self); 181 | NSString *domainName = [NSString stringWithFormat:@"%@.%@", className, propertyName]; 182 | POPAnimatableProperty *property = [POPAnimatableProperty propertyWithName:domainName initializer: ^(POPMutableAnimatableProperty *prop) { 183 | prop.readBlock = readBlock; 184 | prop.writeBlock = writeBlock; 185 | prop.threshold = threshold; 186 | }]; 187 | 188 | NSMutableDictionary *animatableProperties = [MCAnimationProxy __animatablePropertiesByClassName]; 189 | 190 | NSMutableDictionary *classProperties = [animatableProperties objectForKey:className]; 191 | if (!classProperties) { 192 | classProperties = [NSMutableDictionary dictionary]; 193 | animatableProperties[className] = classProperties; 194 | } 195 | 196 | classProperties[propertyName] = property; 197 | } 198 | 199 | @end 200 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCBasicAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCBasicAnimation.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAnimationProxy.h" 10 | #import "MCShorthand.h" 11 | 12 | @interface MCBasicAnimation : MCAnimationProxy 13 | 14 | @property (assign, nonatomic) CFTimeInterval duration; 15 | @property (strong, nonatomic) CAMediaTimingFunction *timingFunction; 16 | 17 | @end 18 | 19 | @interface NSObject (MCBasicAnimation) 20 | 21 | @property (assign, nonatomic) CFTimeInterval pop_duration; 22 | 23 | - (instancetype)pop_linear; 24 | - (instancetype)pop_easeIn; 25 | - (instancetype)pop_easeOut; 26 | - (instancetype)pop_easeInEaseOut; 27 | 28 | @end 29 | 30 | #ifdef MCANIMATE_SHORTHAND 31 | 32 | @interface NSObject (MCBasicAnimation_DropPrefix) 33 | 34 | @property (assign, nonatomic) CFTimeInterval duration; 35 | 36 | - (instancetype)linear; 37 | - (instancetype)easeIn; 38 | - (instancetype)easeOut; 39 | - (instancetype)easeInEaseOut; 40 | 41 | @end 42 | 43 | @implementation NSObject (MCBasicAnimation_DropPrefix) 44 | 45 | MCSHORTHAND_PROPERTY(duration, Duration, CFTimeInterval) 46 | MCSHORTHAND_GETTER(linear, instancetype) 47 | MCSHORTHAND_GETTER(easeIn, instancetype) 48 | MCSHORTHAND_GETTER(easeOut, instancetype) 49 | MCSHORTHAND_GETTER(easeInEaseOut, instancetype) 50 | 51 | @end 52 | 53 | #endif -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCBasicAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCBasicAnimation.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCBasicAnimation.h" 10 | #import 11 | 12 | static char kBasicAnimationProxyKey; 13 | 14 | @implementation MCBasicAnimation 15 | 16 | - (instancetype)initWithObject:(id)object { 17 | self = [super initWithObject:object]; 18 | if (self) { 19 | _duration = 0.4; 20 | } 21 | return self; 22 | } 23 | 24 | + (NSString *)propertyNameForSelector:(SEL)selector { 25 | return [self propertyNameFromSetterSelector:selector]; 26 | } 27 | 28 | - (POPPropertyAnimation *)propertyAnimation { 29 | POPBasicAnimation *animation = [POPBasicAnimation animation]; 30 | animation.duration = self.duration; 31 | animation.timingFunction = self.timingFunction; 32 | 33 | animation.beginTime = [self.object pop_beginTime]; 34 | animation.delegate = [self.object pop_delegate]; 35 | [self.object setPop_delegate:nil]; 36 | 37 | return animation; 38 | } 39 | 40 | @end 41 | 42 | @implementation NSObject (MCBasicAnimation) 43 | 44 | - (MCBasicAnimation *)mc_basicAnimationProxy { 45 | MCBasicAnimation *proxy = objc_getAssociatedObject(self, &kBasicAnimationProxyKey); 46 | if (!proxy) { 47 | proxy = [[MCBasicAnimation alloc] initWithObject:self]; 48 | objc_setAssociatedObject(self, &kBasicAnimationProxyKey, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 49 | } 50 | return proxy; 51 | } 52 | 53 | - (CFTimeInterval)pop_duration { 54 | return [self mc_basicAnimationProxy].duration; 55 | } 56 | 57 | - (void)setPop_duration:(CFTimeInterval)duration { 58 | [self mc_basicAnimationProxy].duration = duration; 59 | } 60 | 61 | - (instancetype)pop_linear { 62 | MCBasicAnimation *proxy = [self mc_basicAnimationProxy]; 63 | proxy.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 64 | return (id) proxy; 65 | } 66 | 67 | - (instancetype)pop_easeIn { 68 | MCBasicAnimation *proxy = [self mc_basicAnimationProxy]; 69 | proxy.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; 70 | return (id) proxy; 71 | } 72 | 73 | - (instancetype)pop_easeOut { 74 | MCBasicAnimation *proxy = [self mc_basicAnimationProxy]; 75 | proxy.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 76 | return (id) proxy; 77 | } 78 | 79 | - (instancetype)pop_easeInEaseOut{ 80 | MCBasicAnimation *proxy = [self mc_basicAnimationProxy]; 81 | proxy.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 82 | return (id) proxy; 83 | } 84 | 85 | @end -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCBeginTime.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MCBeginTime.h 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 11/11/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface NSObject (MCBeginTime) 12 | 13 | @property (assign, nonatomic) CFTimeInterval pop_beginTime; 14 | 15 | @end 16 | 17 | #ifdef MCANIMATE_SHORTHAND 18 | 19 | @interface NSObject (MCBeginTime_DropPrefix) 20 | 21 | @property (assign, nonatomic) CFTimeInterval beginTime; 22 | 23 | @end 24 | 25 | @implementation NSObject (MCBeginTime_DropPrefix) 26 | 27 | MCSHORTHAND_PROPERTY(beginTime, BeginTime, CFTimeInterval) 28 | 29 | @end 30 | 31 | #endif -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCBeginTime.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MCBeginTime.m 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 11/11/14. 6 | // 7 | // 8 | 9 | #import "MCBeginTime.h" 10 | 11 | #import 12 | 13 | static char kMCAnimateBeginTimeKey; 14 | 15 | @implementation NSObject (MCBeginTime) 16 | 17 | - (CFTimeInterval)pop_beginTime { 18 | NSNumber *beginTime = objc_getAssociatedObject(self, &kMCAnimateBeginTimeKey); 19 | return [beginTime doubleValue]; 20 | } 21 | 22 | - (void)setPop_beginTime:(CFTimeInterval)beginTime { 23 | objc_setAssociatedObject(self, &kMCAnimateBeginTimeKey, @(beginTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCDecayAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCDecayAnimation.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 29/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAnimationProxy.h" 10 | #import "MCShorthand.h" 11 | 12 | @interface MCDecayAnimation : MCAnimationProxy 13 | 14 | @property (assign, nonatomic) CGFloat deceleration; 15 | 16 | @end 17 | 18 | @interface NSObject (MCDecayAnimation) 19 | 20 | @property (assign, nonatomic) CGFloat pop_decayDeceleration; 21 | 22 | - (instancetype)pop_decay; 23 | 24 | @end 25 | 26 | #ifdef MCANIMATE_SHORTHAND 27 | 28 | @interface NSObject (MCDecayAnimation_DropPrefix) 29 | 30 | @property (assign, nonatomic) CGFloat decayDeceleration; 31 | 32 | - (instancetype)decay; 33 | 34 | @end 35 | 36 | @implementation NSObject (MCDecayAnimation_DropPrefix) 37 | 38 | MCSHORTHAND_PROPERTY(decayDeceleration, DecayDeceleration, CGFloat) 39 | MCSHORTHAND_GETTER(decay, instancetype) 40 | 41 | @end 42 | 43 | #endif -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCDecayAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCDecayAnimation.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 29/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCDecayAnimation.h" 10 | #import "MCVelocityProxyInternal.h" 11 | 12 | #import 13 | 14 | static char kDecayAnimationProxyKey; 15 | 16 | @implementation MCDecayAnimation 17 | 18 | - (instancetype)initWithObject:(id)object { 19 | self = [super initWithObject:object]; 20 | if (self) { 21 | _deceleration = 0.998; 22 | } 23 | return self; 24 | } 25 | 26 | + (NSString *)propertyNameForSelector:(SEL)selector { 27 | return [self propertyNameFromGetterSelector:selector]; 28 | } 29 | 30 | - (POPPropertyAnimation *)propertyAnimation { 31 | POPDecayAnimation *animation = [POPDecayAnimation animation]; 32 | animation.deceleration = self.deceleration; 33 | 34 | id velocity = [self.object mc_velocityProxy].velocity; 35 | if (velocity) { 36 | animation.velocity = velocity; 37 | [self.object mc_velocityProxy].velocity = nil; 38 | } 39 | 40 | animation.beginTime = [self.object pop_beginTime]; 41 | animation.delegate = [self.object pop_delegate]; 42 | [self.object setPop_delegate:nil]; 43 | 44 | return animation; 45 | } 46 | 47 | @end 48 | 49 | @implementation NSObject (MCDecayAnimation) 50 | 51 | - (MCDecayAnimation *)mc_decayAnimationProxy { 52 | MCDecayAnimation *proxy = objc_getAssociatedObject(self, &kDecayAnimationProxyKey); 53 | if (!proxy) { 54 | proxy = [[MCDecayAnimation alloc] initWithObject:self]; 55 | objc_setAssociatedObject(self, &kDecayAnimationProxyKey, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 56 | } 57 | return proxy; 58 | } 59 | 60 | - (instancetype)pop_decay { 61 | return (id)[self mc_decayAnimationProxy]; 62 | } 63 | 64 | - (CGFloat)pop_decayDeceleration { 65 | return [self mc_decayAnimationProxy].deceleration; 66 | } 67 | 68 | - (void)setPop_decayDeceleration:(CGFloat)decayDeceleration { 69 | [self mc_decayAnimationProxy].deceleration = decayDeceleration; 70 | } 71 | 72 | @end 73 | 74 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCSpringAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCSpringAnimation.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 29/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAnimationProxy.h" 10 | #import "MCShorthand.h" 11 | 12 | @interface MCSpringAnimation : MCAnimationProxy 13 | 14 | @property (assign, nonatomic) CGFloat springBounciness; 15 | @property (assign, nonatomic) CGFloat springSpeed; 16 | 17 | @end 18 | 19 | @interface NSObject (MCSpringAnimation) 20 | 21 | @property (assign, nonatomic) CGFloat pop_springBounciness; 22 | @property (assign, nonatomic) CGFloat pop_springSpeed; 23 | 24 | - (instancetype)pop_spring; 25 | 26 | @end 27 | 28 | #ifdef MCANIMATE_SHORTHAND 29 | 30 | @interface NSObject (MCSpringAnimation_DropPrefix) 31 | 32 | @property (assign, nonatomic) CGFloat springBounciness; 33 | @property (assign, nonatomic) CGFloat springSpeed; 34 | 35 | - (instancetype)spring; 36 | 37 | @end 38 | 39 | @implementation NSObject (MCSpringAnimation_DropPrefix) 40 | 41 | MCSHORTHAND_PROPERTY(springBounciness, SpringBounciness, CGFloat) 42 | MCSHORTHAND_PROPERTY(springSpeed, SpringSpeed, CGFloat) 43 | MCSHORTHAND_GETTER(spring, instancetype) 44 | 45 | @end 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCSpringAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCSpringAnimation.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 29/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCSpringAnimation.h" 10 | #import "MCVelocityProxyInternal.h" 11 | 12 | #import 13 | 14 | static char kSpringAnimationProxyKey; 15 | 16 | @implementation MCSpringAnimation 17 | 18 | - (instancetype)initWithObject:(id)object { 19 | self = [super initWithObject:object]; 20 | if (self) { 21 | _springBounciness = 4; 22 | _springSpeed = 12; 23 | } 24 | return self; 25 | } 26 | 27 | + (NSString *)propertyNameForSelector:(SEL)selector { 28 | return [self propertyNameFromSetterSelector:selector]; 29 | } 30 | 31 | - (POPPropertyAnimation *)propertyAnimation { 32 | POPSpringAnimation *animation = [POPSpringAnimation animation]; 33 | animation.springBounciness = self.springBounciness; 34 | animation.springSpeed = self.springSpeed; 35 | 36 | id velocity = [self.object mc_velocityProxy].velocity; 37 | if (velocity) { 38 | animation.velocity = velocity; 39 | [self.object mc_velocityProxy].velocity = nil; 40 | } 41 | 42 | animation.beginTime = [self.object pop_beginTime]; 43 | animation.delegate = [self.object pop_delegate]; 44 | [self.object setPop_delegate:nil]; 45 | 46 | return animation; 47 | } 48 | 49 | @end 50 | 51 | @implementation NSObject (MCSpringAnimation) 52 | 53 | - (MCSpringAnimation *)mc_springAnimationProxy { 54 | MCSpringAnimation *proxy = objc_getAssociatedObject(self, &kSpringAnimationProxyKey); 55 | if (!proxy) { 56 | proxy = [[MCSpringAnimation alloc] initWithObject:self]; 57 | objc_setAssociatedObject(self, &kSpringAnimationProxyKey, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 58 | } 59 | return proxy; 60 | } 61 | 62 | - (instancetype)pop_spring { 63 | return (id) [self mc_springAnimationProxy]; 64 | } 65 | 66 | - (CGFloat)pop_springBounciness { 67 | return [self mc_springAnimationProxy].springBounciness; 68 | } 69 | 70 | - (void)setPop_springBounciness:(CGFloat)springBounciness { 71 | [self mc_springAnimationProxy].springBounciness = springBounciness; 72 | } 73 | 74 | - (CGFloat)pop_springSpeed { 75 | return [self mc_springAnimationProxy].springSpeed; 76 | } 77 | 78 | - (void)setPop_springSpeed:(CGFloat)springSpeed { 79 | [self mc_springAnimationProxy].springSpeed = springSpeed; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCStopProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCStopProxy.h 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 10/5/14. 6 | // 7 | // 8 | 9 | #import "MCProxy.h" 10 | #import "MCShorthand.h" 11 | 12 | @interface MCStopProxy : MCProxy 13 | 14 | @end 15 | 16 | @interface NSObject (MCStopProxy) 17 | 18 | - (instancetype)pop_stop; 19 | 20 | @end 21 | 22 | #ifdef MCANIMATE_SHORTHAND 23 | 24 | @interface NSObject (MCStopProxy_DropPrefix) 25 | 26 | @property (assign, nonatomic) CFTimeInterval duration; 27 | 28 | - (instancetype)stop; 29 | 30 | @end 31 | 32 | @implementation NSObject (MCStopProxy_DropPrefix) 33 | 34 | MCSHORTHAND_GETTER(stop, instancetype) 35 | 36 | @end 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/MCStopProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCStopProxy.m 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 10/5/14. 6 | // 7 | // 8 | 9 | #import "MCStopProxy.h" 10 | 11 | #import 12 | #import 13 | 14 | static char kStopAnimationProxyKey; 15 | 16 | @implementation MCStopProxy 17 | 18 | + (NSString *)propertyNameForSelector:(SEL)selector { 19 | return [self propertyNameFromGetterSelector:selector]; 20 | } 21 | 22 | - (void)completeInvocationWithPropertyName:(NSString *)propertyName andValue:(id)value { 23 | if ([propertyName hasPrefix:@"pop_"]) { 24 | propertyName = [propertyName substringFromIndex:4]; 25 | } 26 | 27 | // remove animation 28 | POPPropertyAnimation *animation = [self.object pop_animationForKey:propertyName]; 29 | if (animation) { 30 | [self.object pop_removeAnimationForKey:propertyName]; 31 | } 32 | } 33 | 34 | @end 35 | 36 | @implementation NSObject (MCStopProxy) 37 | 38 | - (MCStopProxy *)mc_stopAnimationProxy { 39 | MCStopProxy *proxy = objc_getAssociatedObject(self, &kStopAnimationProxyKey); 40 | if (!proxy) { 41 | proxy = [[MCStopProxy alloc] initWithObject:self]; 42 | objc_setAssociatedObject(self, &kStopAnimationProxyKey, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 43 | } 44 | return proxy; 45 | } 46 | 47 | - (instancetype)pop_stop { 48 | return (id)[self mc_stopAnimationProxy]; 49 | } 50 | 51 | @end -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/NSArray+MCSequence.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+MCSequence.h 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 11/11/14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (MCSequence) 12 | 13 | - (void)pop_sequenceWithInterval:(CFTimeInterval)interval animations:(void (^)(id object, NSInteger index))animations completion:(void (^)(BOOL finished))completion; 14 | 15 | @end 16 | 17 | #ifdef MCANIMATE_SHORTHAND 18 | 19 | @interface NSArray (MCSequence_DropPrefix) 20 | 21 | - (void)sequenceWithInterval:(CFTimeInterval)interval animations:(void (^)(id object, NSInteger index))animations completion:(void (^)(BOOL finished))completion; 22 | 23 | @end 24 | 25 | @implementation NSArray (MCSequence_DropPrefix) 26 | 27 | - (void)sequenceWithInterval:(CFTimeInterval)interval animations:(void (^)(id object, NSInteger index))animations completion:(void (^)(BOOL finished))completion { 28 | [self pop_sequenceWithInterval:interval animations:animations completion:completion]; 29 | } 30 | 31 | @end 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /POP+MCAnimate/Animations/NSArray+MCSequence.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+MCSequence.m 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 11/11/14. 6 | // 7 | // 8 | 9 | #import "NSArray+MCSequence.h" 10 | #import "MCBeginTime.h" 11 | #import "MCAnimationGroup.h" 12 | 13 | #import 14 | 15 | @implementation NSArray (MCSequence) 16 | 17 | - (void)pop_sequenceWithInterval:(CFTimeInterval)interval animations:(void (^)(id object, NSInteger index))animations completion:(void (^)(BOOL finished))completion { 18 | __weak typeof(self) weakSelf = self; 19 | [NSObject pop_animate: ^{ 20 | typeof(self) strongSelf = weakSelf; 21 | for (int i = 0; i < strongSelf.count; i++) { 22 | id object = strongSelf[i]; 23 | [object setPop_beginTime:CACurrentMediaTime() + i * interval]; 24 | animations(object, i); 25 | } 26 | } completion:completion]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /POP+MCAnimate/Group/MCAnimationGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCAnimationGroup.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 3/5/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface MCAnimationGroup : NSObject 13 | 14 | @property (assign, nonatomic, getter = isFinished, readonly) BOOL finished; 15 | @property (copy, nonatomic) void (^completionBlock)(BOOL finished); 16 | 17 | - (void)addAnimation:(POPAnimation *)animation; 18 | - (void)removeAnimation:(POPAnimation *)animation finished:(BOOL)finished; 19 | 20 | @end 21 | 22 | @interface NSObject (MCAnimationGroup) 23 | 24 | + (void)pop_animate:(void (^)(void))animations completion:(void (^)(BOOL finished))completion; 25 | 26 | @end 27 | 28 | #ifdef MCANIMATE_SHORTHAND 29 | 30 | @interface NSObject (MCAnimationGroup_DropPrefix) 31 | 32 | + (void)animate:(void (^)(void))animations completion:(void (^)(BOOL finished))completion; 33 | 34 | @end 35 | 36 | @implementation NSObject (MCAnimationGroup_DropPrefix) 37 | 38 | + (void)animate:(void (^)(void))animations completion:(void (^)(BOOL finished))completion { 39 | [self pop_animate:animations completion:completion]; 40 | } 41 | 42 | @end 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /POP+MCAnimate/Group/MCAnimationGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCAnimationGroup.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 3/5/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAnimationGroup.h" 10 | #import "MCAnimationGroupInternal.h" 11 | 12 | @interface MCAnimationGroup () 13 | 14 | @property (strong, nonatomic) NSMutableSet *remainingAnimations; 15 | @property (strong, nonatomic) NSMapTable *animationsFinished; 16 | 17 | @end 18 | 19 | @implementation MCAnimationGroup 20 | 21 | - (instancetype)init { 22 | self = [super init]; 23 | if (self) { 24 | _remainingAnimations = [NSMutableSet set]; 25 | _animationsFinished = [NSMapTable strongToStrongObjectsMapTable]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)addAnimation:(POPAnimation *)animation { 31 | animation.completionBlock = ^(POPAnimation *animation, BOOL finished) { 32 | for (MCAnimationGroup *group in [NSObject mc_animationGroups]) { 33 | [group removeAnimation:animation finished:finished]; 34 | } 35 | }; 36 | 37 | [self.animationsFinished setObject:@(NO) forKey:animation]; 38 | [self.remainingAnimations addObject:animation]; 39 | } 40 | 41 | - (void)removeAnimation:(POPAnimation *)animation finished:(BOOL)finished { 42 | if (![self.remainingAnimations containsObject:animation]) { 43 | return; 44 | } 45 | 46 | [self.animationsFinished setObject:@(finished) forKey:animation]; 47 | [self.remainingAnimations removeObject:animation]; 48 | 49 | if ([self.remainingAnimations count] < 1) { 50 | dispatch_async(dispatch_get_main_queue(), ^{ 51 | if (self.completionBlock) { 52 | self.completionBlock([self isFinished]); 53 | } 54 | 55 | [self.animationsFinished removeAllObjects]; 56 | }); 57 | } 58 | } 59 | 60 | #pragma mark - Properties 61 | 62 | - (BOOL)isFinished { 63 | for (POPAnimation *animation in self.animationsFinished) { 64 | if (![[self.animationsFinished objectForKey:animation] boolValue]) { 65 | return NO; 66 | } 67 | } 68 | return YES; 69 | } 70 | 71 | @end 72 | 73 | @implementation NSObject (MCAnimationGroup) 74 | 75 | + (void)pop_animate:(void (^)(void))animations completion:(void (^)(BOOL))completion { 76 | MCAnimationGroup *group = [[MCAnimationGroup alloc] init]; 77 | [[self mc_animationGroups] addObject:group]; 78 | 79 | __weak MCAnimationGroup *weakGroup = group; 80 | group.completionBlock = ^(BOOL finished) { 81 | MCAnimationGroup *strongGroup = weakGroup; 82 | [[self mc_animationGroups] removeObject:strongGroup]; 83 | 84 | if (completion) { 85 | completion(finished); 86 | } 87 | }; 88 | 89 | [self mc_setActiveAnimationGroup:group]; 90 | 91 | if (animations) { 92 | animations(); 93 | } 94 | 95 | [self mc_setActiveAnimationGroup:nil]; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /POP+MCAnimate/Group/MCAnimationGroupInternal.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MCAnimationGroupInternal.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 3/5/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAnimationGroup.h" 10 | 11 | @interface NSObject (MCAnimationGroupInternal) 12 | 13 | + (NSMutableArray *)mc_animationGroups; 14 | + (MCAnimationGroup *)mc_activeAnimationGroup; 15 | + (void)mc_setActiveAnimationGroup:(MCAnimationGroup *)animationGroup; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /POP+MCAnimate/Group/MCAnimationGroupInternal.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MCAnimationGroupInternal.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 3/5/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAnimationGroupInternal.h" 10 | #import 11 | 12 | static char kAnimationGroupsKey; 13 | static char kActiveAnimationGroupKey; 14 | 15 | @implementation NSObject (MCAnimationGroupInternal) 16 | 17 | + (NSMutableArray *)mc_animationGroups { 18 | NSMutableArray *array = objc_getAssociatedObject(self, &kAnimationGroupsKey); 19 | if (!array) { 20 | array = [NSMutableArray array]; 21 | objc_setAssociatedObject(self, &kAnimationGroupsKey, array, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 22 | } 23 | return array; 24 | } 25 | 26 | + (MCAnimationGroup *)mc_activeAnimationGroup { 27 | return objc_getAssociatedObject(self, &kActiveAnimationGroupKey); 28 | } 29 | 30 | + (void)mc_setActiveAnimationGroup:(MCAnimationGroup *)animationGroup { 31 | objc_setAssociatedObject(self, &kActiveAnimationGroupKey, animationGroup, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /POP+MCAnimate/Internal/MCProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCProxy.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MCProxy : NSProxy 12 | 13 | @property (weak, nonatomic, readonly) id object; 14 | 15 | - (instancetype)initWithObject:(id)object; 16 | 17 | #pragma mark - Required 18 | 19 | // subclasses should override the following methods 20 | + (NSString *)propertyNameForSelector:(SEL)selector; 21 | - (void)completeInvocationWithPropertyName:(NSString *)propertyName andValue:(id)value; 22 | 23 | #pragma mark - Utility 24 | 25 | + (NSString *)propertyNameFromSetterSelector:(SEL)selector; 26 | + (NSString *)propertyNameFromGetterSelector:(SEL)selector; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /POP+MCAnimate/Internal/MCProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCProxy.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCProxy.h" 10 | #import "NSNumber+MCAdditions.h" 11 | 12 | @interface MCProxy () 13 | 14 | @property (weak, nonatomic) id object; 15 | 16 | @end 17 | 18 | @implementation MCProxy 19 | 20 | - (instancetype)initWithObject:(id)object { 21 | _object = object; 22 | return self; 23 | } 24 | 25 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { 26 | return [self.object methodSignatureForSelector:sel]; 27 | } 28 | 29 | - (void)forwardInvocation:(NSInvocation *)invocation { 30 | NSString *propertyName = [[self class] propertyNameForSelector:invocation.selector]; 31 | NSUInteger argumentCount = [[invocation methodSignature] numberOfArguments]; 32 | 33 | // wrap argument in NSValue/NSNumber if necessary 34 | id value = nil; 35 | if (argumentCount > 2) { 36 | NSMethodSignature *signature = [[self.object class] instanceMethodSignatureForSelector:NSSelectorFromString(propertyName)]; 37 | 38 | const char *property_type = [signature methodReturnType]; 39 | 40 | if (!property_type) { 41 | [NSException raise:NSInternalInconsistencyException format:@"Property '%@' cannot be found on class <%@>.", propertyName, [[self.object class] description]]; 42 | } 43 | else if ([[NSString stringWithUTF8String:property_type] rangeOfString:@"@"].location != NSNotFound) { 44 | __unsafe_unretained id argument = nil; 45 | [invocation getArgument:&argument atIndex:2]; 46 | 47 | value = argument; 48 | } 49 | else { 50 | NSUInteger bufferSize = 0; 51 | NSGetSizeAndAlignment(property_type, &bufferSize, NULL); 52 | void *buffer = malloc(bufferSize); 53 | 54 | [invocation getArgument:buffer atIndex:2]; 55 | value = [NSNumber numberWithValue:buffer objCType:property_type]; 56 | 57 | free(buffer); 58 | } 59 | } 60 | 61 | [self completeInvocationWithPropertyName:propertyName andValue:value]; 62 | } 63 | 64 | #pragma mark - Methods 65 | 66 | + (NSString *)propertyNameForSelector:(SEL)selector { 67 | [NSException raise:NSInternalInconsistencyException format:@"Use a concrete subclass of MCProxy."]; 68 | return nil; 69 | } 70 | 71 | - (void)completeInvocationWithPropertyName:(NSString *)propertyName andValue:(id)value { 72 | [NSException raise:NSInternalInconsistencyException format:@"Use a concrete subclass of MCProxy."]; 73 | } 74 | 75 | #pragma mark - Utility 76 | 77 | + (NSString *)propertyNameFromSetterSelector:(SEL)selector { 78 | NSString *selectorName = NSStringFromSelector(selector); 79 | if (![selectorName hasPrefix:@"set"]) { 80 | [NSException raise:NSInternalInconsistencyException format:@"%@ only takes setters.", [self description]]; 81 | } 82 | 83 | NSString *propertyName = [selectorName substringWithRange:NSMakeRange(3, [selectorName length]-4)]; 84 | propertyName = [[[propertyName substringWithRange:NSMakeRange(0, 1)] lowercaseString] stringByAppendingString:[propertyName substringFromIndex:1]]; 85 | 86 | return propertyName; 87 | } 88 | 89 | + (NSString *)propertyNameFromGetterSelector:(SEL)selector { 90 | NSString *selectorName = NSStringFromSelector(selector); 91 | if ([selectorName hasPrefix:@"set"]) { 92 | [NSException raise:NSInternalInconsistencyException format:@"%@ only takes setters.", [self description]]; 93 | } 94 | 95 | return selectorName; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /POP+MCAnimate/Internal/NSNumber+MCAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSNumber+MCAdditions.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSNumber (MCAdditions) 12 | 13 | + (instancetype)numberWithValue:(const void *)value objCType:(const char *)type; 14 | - (instancetype)initWithValue:(const void *)value objCType:(const char *)type; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /POP+MCAnimate/Internal/NSNumber+MCAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSNumber+MCAdditions.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "NSNumber+MCAdditions.h" 10 | 11 | @implementation NSNumber (MCAdditions) 12 | 13 | + (instancetype)numberWithValue:(const void *)value objCType:(const char *)type { 14 | return [[self alloc] initWithValue:value objCType:type]; 15 | } 16 | 17 | /// For the constants see: 18 | - (instancetype)initWithValue:(const void *)value objCType:(const char *)type { 19 | if ('^' == *type 20 | && nil == *(__unsafe_unretained id *)value) return nil; // nil should stay nil, even if it's technically a (void *) 21 | id number = [NSNumber alloc]; 22 | switch (*type) { 23 | case 'c': // BOOL, char 24 | return [number initWithChar:*(char *)value]; 25 | 26 | case 'C': return [number initWithUnsignedChar:*(unsigned char *)value]; 27 | 28 | case 's': return [number initWithShort:*(short *)value]; 29 | 30 | case 'S': return [number initWithUnsignedShort:*(unsigned short *)value]; 31 | 32 | case 'i': return [number initWithInt:*(int *)value]; 33 | 34 | case 'I': return [number initWithUnsignedInt:*(unsigned *)value]; 35 | 36 | case 'l': return [number initWithLong:*(long *)value]; 37 | 38 | case 'L': return [number initWithUnsignedLong:*(unsigned long *)value]; 39 | 40 | case 'q': return [number initWithLongLong:*(long long *)value]; 41 | 42 | case 'Q': return [number initWithUnsignedLongLong:*(unsigned long long *)value]; 43 | 44 | case 'f': return [number initWithFloat:*(float *)value]; 45 | 46 | case 'd': return [number initWithDouble:*(double *)value]; 47 | 48 | case '@': return *(__unsafe_unretained id *)value; 49 | 50 | case '^': // pointer, no string stuff supported right now 51 | case '{': // struct, only simple ones containing only basic types right now 52 | case '[': // array, of whatever, just gets the address 53 | return (id)[[NSValue alloc] initWithBytes:value objCType:type]; 54 | } 55 | 56 | //NSLog(@"converting unknown format %s", aTypeDescription); 57 | return (id)[[NSValue alloc] initWithBytes:value objCType:type]; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /POP+MCAnimate/POP+MCAnimate.h: -------------------------------------------------------------------------------- 1 | // 2 | // POP+MCAnimate.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "NSArray+MCSequence.h" 12 | #import "CALayer+MCShorthand.h" 13 | #import "UIView+MCShorthand.h" 14 | 15 | #import "MCAnimationGroup.h" 16 | #import "MCVelocityProxy.h" 17 | #import "MCStopProxy.h" 18 | #import "MCBeginTime.h" 19 | 20 | #import "MCBasicAnimation.h" 21 | #import "MCDecayAnimation.h" 22 | #import "MCSpringAnimation.h" 23 | 24 | -------------------------------------------------------------------------------- /POP+MCAnimate/Shorthand/CALayer+MCShorthand.h: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+MCShorthand.h 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 4/5/14. 6 | // 7 | // 8 | 9 | #import 10 | #import "MCShorthand.h" 11 | 12 | @interface CALayer (MCShorthand) 13 | 14 | @property (assign, nonatomic) CGFloat pop_positionX; 15 | @property (assign, nonatomic) CGFloat pop_positionY; 16 | @property (assign, nonatomic) CGFloat pop_rotation; 17 | @property (assign, nonatomic) CGFloat pop_rotationX; 18 | @property (assign, nonatomic) CGFloat pop_rotationY; 19 | @property (assign, nonatomic) CGFloat pop_scaleX; 20 | @property (assign, nonatomic) CGFloat pop_scaleY; 21 | @property (assign, nonatomic) CGPoint pop_scaleXY; 22 | @property (assign, nonatomic) CGFloat pop_translationX; 23 | @property (assign, nonatomic) CGPoint pop_translationXY; 24 | @property (assign, nonatomic) CGFloat pop_translationY; 25 | @property (assign, nonatomic) CGFloat pop_translationZ; 26 | @property (assign, nonatomic) CGSize pop_size; 27 | 28 | @end 29 | 30 | #ifdef MCANIMATE_SHORTHAND 31 | 32 | @interface CALayer (MCShorthand_DropPrefix) 33 | 34 | @property (assign, nonatomic) CGFloat positionX; 35 | @property (assign, nonatomic) CGFloat positionY; 36 | @property (assign, nonatomic) CGFloat rotation; 37 | @property (assign, nonatomic) CGFloat rotationX; 38 | @property (assign, nonatomic) CGFloat rotationY; 39 | @property (assign, nonatomic) CGFloat scaleX; 40 | @property (assign, nonatomic) CGFloat scaleY; 41 | @property (assign, nonatomic) CGPoint scaleXY; 42 | @property (assign, nonatomic) CGFloat translationX; 43 | @property (assign, nonatomic) CGPoint translationXY; 44 | @property (assign, nonatomic) CGFloat translationY; 45 | @property (assign, nonatomic) CGFloat translationZ; 46 | @property (assign, nonatomic) CGSize size; 47 | 48 | @end 49 | 50 | @implementation CALayer (MCShorthand_DropPrefix) 51 | 52 | MCSHORTHAND_PROPERTY(positionX, PositionX, CGFloat) 53 | MCSHORTHAND_PROPERTY(positionY, PositionY, CGFloat) 54 | MCSHORTHAND_PROPERTY(rotation, Rotation, CGFloat) 55 | MCSHORTHAND_PROPERTY(rotationX, RotationX, CGFloat) 56 | MCSHORTHAND_PROPERTY(rotationY, RotationY, CGFloat) 57 | MCSHORTHAND_PROPERTY(scaleX, ScaleX, CGFloat) 58 | MCSHORTHAND_PROPERTY(scaleY, ScaleY, CGFloat) 59 | MCSHORTHAND_PROPERTY(scaleXY, ScaleXY, CGPoint) 60 | MCSHORTHAND_PROPERTY(translationX, TranslationX, CGFloat) 61 | MCSHORTHAND_PROPERTY(translationXY, TranslationXY, CGPoint) 62 | MCSHORTHAND_PROPERTY(translationY, TranslationY, CGFloat) 63 | MCSHORTHAND_PROPERTY(translationZ, TranslationZ, CGFloat) 64 | MCSHORTHAND_PROPERTY(size, Size, CGSize) 65 | 66 | @end 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /POP+MCAnimate/Shorthand/CALayer+MCShorthand.m: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+MCShorthand.m 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 4/5/14. 6 | // 7 | // 8 | 9 | #import "CALayer+MCShorthand.h" 10 | #import "POPLayerExtras.h" 11 | 12 | @implementation CALayer (MCShorthand) 13 | 14 | #pragma mark - Position 15 | 16 | - (CGFloat)pop_positionX { 17 | return self.position.x; 18 | } 19 | 20 | - (void)setPop_positionX:(CGFloat)pop_positionX { 21 | CGPoint p = self.position; 22 | p.x = pop_positionX; 23 | self.position = p; 24 | } 25 | 26 | - (CGFloat)pop_positionY { 27 | return self.position.y; 28 | } 29 | 30 | - (void)setPop_positionY:(CGFloat)pop_positionY { 31 | CGPoint p = self.position; 32 | p.y = pop_positionY; 33 | self.position = p; 34 | } 35 | 36 | #pragma mark - Rotation 37 | 38 | - (CGFloat)pop_rotation { 39 | return POPLayerGetRotation(self); 40 | } 41 | 42 | - (void)setPop_rotation:(CGFloat)rotation { 43 | POPLayerSetRotation(self, rotation); 44 | } 45 | 46 | - (CGFloat)pop_rotationX { 47 | return POPLayerGetRotationX(self); 48 | } 49 | 50 | - (void)setPop_rotationX:(CGFloat)pop_rotationX { 51 | POPLayerSetRotationX(self, pop_rotationX); 52 | } 53 | 54 | - (CGFloat)pop_rotationY { 55 | return POPLayerGetRotationY(self); 56 | } 57 | 58 | - (void)setPop_rotationY:(CGFloat)pop_rotationY { 59 | POPLayerSetRotationY(self, pop_rotationY); 60 | } 61 | 62 | #pragma mark - Scale 63 | 64 | - (CGFloat)pop_scaleX { 65 | return POPLayerGetScaleX(self); 66 | } 67 | 68 | - (void)setPop_scaleX:(CGFloat)pop_scaleX { 69 | POPLayerSetScaleX(self, pop_scaleX); 70 | } 71 | 72 | - (CGFloat)pop_scaleY { 73 | return POPLayerGetScaleY(self); 74 | } 75 | 76 | - (void)setPop_scaleY:(CGFloat)pop_scaleY { 77 | POPLayerSetScaleY(self, pop_scaleY); 78 | } 79 | 80 | - (CGPoint)pop_scaleXY { 81 | return POPLayerGetScaleXY(self); 82 | } 83 | 84 | - (void)setPop_scaleXY:(CGPoint)scaleXY { 85 | POPLayerSetScaleXY(self, scaleXY); 86 | } 87 | 88 | #pragma mark - Translation 89 | 90 | - (CGFloat)pop_translationX { 91 | return POPLayerGetTranslationX(self); 92 | } 93 | 94 | - (void)setPop_translationX:(CGFloat)pop_translationX { 95 | POPLayerSetTranslationX(self, pop_translationX); 96 | } 97 | 98 | - (CGPoint)pop_translationXY { 99 | return POPLayerGetTranslationXY(self); 100 | } 101 | 102 | - (void)setPop_translationXY:(CGPoint)pop_translationXY { 103 | POPLayerSetTranslationXY(self, pop_translationXY); 104 | } 105 | 106 | - (CGFloat)pop_translationY { 107 | return POPLayerGetTranslationY(self); 108 | } 109 | 110 | - (void)setPop_translationY:(CGFloat)pop_translationY { 111 | POPLayerSetTranslationY(self, pop_translationY); 112 | } 113 | 114 | - (CGFloat)pop_translationZ { 115 | return POPLayerGetTranslationZ(self); 116 | } 117 | 118 | - (void)setPop_translationZ:(CGFloat)pop_translationZ { 119 | POPLayerSetTranslationZ(self, pop_translationZ); 120 | } 121 | 122 | #pragma mark - Size 123 | 124 | - (CGSize)pop_size { 125 | return [self bounds].size; 126 | } 127 | 128 | - (void)setPop_size:(CGSize)size { 129 | CGRect b = [self bounds]; 130 | b.size = size; 131 | [self setBounds:b]; 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /POP+MCAnimate/Shorthand/MCShorthand.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCShorthand.h 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 5/5/14. 6 | // 7 | // 8 | 9 | #ifndef Pods_MCShorthand_h 10 | #define Pods_MCShorthand_h 11 | 12 | #define MCSHORTHAND_GETTER(getter, ctype) \ 13 | - (ctype)getter { \ 14 | return [self pop_##getter]; \ 15 | } 16 | 17 | #define MCSHORTHAND_SETTER(setter, getter, ctype) \ 18 | - (void)set ## setter :(ctype)value { \ 19 | [self setPop_ ## getter :value]; \ 20 | } 21 | 22 | #define MCSHORTHAND_PROPERTY(getter, setter, ctype) \ 23 | MCSHORTHAND_GETTER (getter, ctype) \ 24 | MCSHORTHAND_SETTER (setter, getter, ctype) 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /POP+MCAnimate/Shorthand/UIView+MCShorthand.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+MCShorthand.h 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 4/5/14. 6 | // 7 | // 8 | 9 | #import 10 | #import "MCShorthand.h" 11 | 12 | @interface UIView (MCShorthand) 13 | 14 | @property (assign, nonatomic) CGFloat pop_scaleX; 15 | @property (assign, nonatomic) CGFloat pop_scaleY; 16 | @property (assign, nonatomic) CGPoint pop_scaleXY; 17 | 18 | @end 19 | 20 | #ifdef MCANIMATE_SHORTHAND 21 | 22 | @interface UIView (MCShorthand_DropPrefix) 23 | 24 | @property (assign, nonatomic) CGFloat scaleX; 25 | @property (assign, nonatomic) CGFloat scaleY; 26 | @property (assign, nonatomic) CGPoint scaleXY; 27 | 28 | @end 29 | 30 | @implementation UIView (MCShorthand_DropPrefix) 31 | 32 | MCSHORTHAND_PROPERTY(scaleX, ScaleX, CGFloat) 33 | MCSHORTHAND_PROPERTY(scaleY, ScaleY, CGFloat) 34 | MCSHORTHAND_PROPERTY(scaleXY, ScaleXY, CGPoint) 35 | 36 | @end 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /POP+MCAnimate/Shorthand/UIView+MCShorthand.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+MCShorthand.m 3 | // Pods 4 | // 5 | // Created by Matthew Cheok on 4/5/14. 6 | // 7 | // 8 | 9 | #import "UIView+MCShorthand.h" 10 | #import "POPLayerExtras.h" 11 | 12 | @implementation UIView (MCShorthand) 13 | 14 | - (CGFloat)pop_scaleX { 15 | return POPLayerGetScaleX(self.layer); 16 | } 17 | 18 | - (void)setPop_scaleX:(CGFloat)scaleX { 19 | POPLayerSetScaleX(self.layer, scaleX); 20 | } 21 | 22 | - (CGFloat)pop_scaleY { 23 | return POPLayerGetScaleY(self.layer); 24 | } 25 | 26 | - (void)setPop_scaleY:(CGFloat)scaleY { 27 | POPLayerSetScaleY(self.layer, scaleY); 28 | } 29 | 30 | - (CGPoint)pop_scaleXY { 31 | return POPLayerGetScaleXY(self.layer); 32 | } 33 | 34 | - (void)setPop_scaleXY:(CGPoint)scaleXY { 35 | POPLayerSetScaleXY(self.layer, scaleXY); 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /POP+MCAnimate/Velocity/MCVelocityProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCVelocityProxy.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCProxy.h" 10 | 11 | 12 | @interface MCVelocityProxy : MCProxy 13 | 14 | @property (copy, nonatomic) id velocity; 15 | 16 | @end 17 | 18 | @interface NSObject (MCVelocityProxy) 19 | 20 | - (instancetype)pop_velocity; 21 | - (void)setPop_velocity:(id)velocity; 22 | 23 | @end 24 | 25 | #ifdef MCANIMATE_SHORTHAND 26 | 27 | @interface NSObject (MCVelocityProxy_DropPrefix) 28 | 29 | - (instancetype)velocity; 30 | 31 | @end 32 | 33 | @implementation NSObject (MCVelocityProxy_DropPrefix) 34 | 35 | MCSHORTHAND_GETTER(velocity, instancetype) 36 | MCSHORTHAND_SETTER(Velocity, velocity, id) 37 | 38 | @end 39 | 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /POP+MCAnimate/Velocity/MCVelocityProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCVelocityProxy.m 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCVelocityProxy.h" 10 | #import "MCVelocityProxyInternal.h" 11 | 12 | #import 13 | 14 | static char kVelocityProxyKey; 15 | 16 | @implementation MCVelocityProxy 17 | 18 | + (NSString *)propertyNameForSelector:(SEL)selector { 19 | NSString *selectorName = NSStringFromSelector(selector); 20 | if (![selectorName hasPrefix:@"set"]) { 21 | [NSException raise:NSInternalInconsistencyException format:@"Spring animation only takes setters."]; 22 | } 23 | 24 | NSString *propertyName = [selectorName substringWithRange:NSMakeRange(3, [selectorName length]-4)]; 25 | propertyName = [[[propertyName substringWithRange:NSMakeRange(0, 1)] lowercaseString] stringByAppendingString:[propertyName substringFromIndex:1]]; 26 | 27 | return propertyName; 28 | } 29 | 30 | - (void)completeInvocationWithPropertyName:(NSString *)propertyName andValue:(id)value { 31 | self.velocity = value; 32 | } 33 | 34 | @end 35 | 36 | @implementation NSObject (MCVelocityProxyInternal) 37 | 38 | - (MCVelocityProxy *)mc_velocityProxy { 39 | MCVelocityProxy *proxy = objc_getAssociatedObject(self, &kVelocityProxyKey); 40 | if (!proxy) { 41 | proxy = [[MCVelocityProxy alloc] initWithObject:self]; 42 | objc_setAssociatedObject(self, &kVelocityProxyKey, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 43 | } 44 | return proxy; 45 | } 46 | 47 | @end 48 | 49 | @implementation NSObject (MCVelocityProxy) 50 | 51 | - (id)pop_velocity { 52 | return (id)[self mc_velocityProxy]; 53 | } 54 | 55 | - (void)setPop_velocity:(id)velocity { 56 | [self mc_velocityProxy].velocity = velocity; 57 | } 58 | 59 | @end -------------------------------------------------------------------------------- /POP+MCAnimate/Velocity/MCVelocityProxyInternal.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCVelocityProxyInternal.h 3 | // POP+MCAnimate 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCVelocityProxy.h" 10 | 11 | @interface NSObject (MCVelocityProxyInternal) 12 | 13 | - (MCVelocityProxy *)mc_velocityProxy; 14 | 15 | @end -------------------------------------------------------------------------------- /POP-Demo/POP-Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 34003227191DFC8300A7CA32 /* POPCGUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34003226191DFC8300A7CA32 /* POPCGUtils.mm */; }; 11 | 34A67E2419114B9A00CCDA78 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A67E2319114B9A00CCDA78 /* Foundation.framework */; }; 12 | 34A67E2619114B9A00CCDA78 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A67E2519114B9A00CCDA78 /* CoreGraphics.framework */; }; 13 | 34A67E2819114B9A00CCDA78 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A67E2719114B9A00CCDA78 /* UIKit.framework */; }; 14 | 34A67E2E19114B9A00CCDA78 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 34A67E2C19114B9A00CCDA78 /* InfoPlist.strings */; }; 15 | 34A67E3019114B9A00CCDA78 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A67E2F19114B9A00CCDA78 /* main.m */; }; 16 | 34A67E3419114B9A00CCDA78 /* MCAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A67E3319114B9A00CCDA78 /* MCAppDelegate.m */; }; 17 | 34A67E3719114B9A00CCDA78 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 34A67E3519114B9A00CCDA78 /* Main.storyboard */; }; 18 | 34A67E3A19114B9A00CCDA78 /* MCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A67E3919114B9A00CCDA78 /* MCViewController.m */; }; 19 | 34A67E3C19114B9A00CCDA78 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 34A67E3B19114B9A00CCDA78 /* Images.xcassets */; }; 20 | 34A67E4319114B9A00CCDA78 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A67E4219114B9A00CCDA78 /* XCTest.framework */; }; 21 | 34A67E4419114B9A00CCDA78 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A67E2319114B9A00CCDA78 /* Foundation.framework */; }; 22 | 34A67E4519114B9A00CCDA78 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A67E2719114B9A00CCDA78 /* UIKit.framework */; }; 23 | 34A67E4D19114B9A00CCDA78 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 34A67E4B19114B9A00CCDA78 /* InfoPlist.strings */; }; 24 | 34A67E4F19114B9A00CCDA78 /* POP_DemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A67E4E19114B9A00CCDA78 /* POP_DemoTests.m */; }; 25 | 9E3818A21A124A8100D39B84 /* MCSequenceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E3818A11A124A8100D39B84 /* MCSequenceController.m */; }; 26 | F292894CD432482195635D85 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F768501D0B147139C73F6F0 /* libPods.a */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 34A67E4619114B9A00CCDA78 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 34A67E1819114B9A00CCDA78 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 34A67E1F19114B9A00CCDA78; 35 | remoteInfo = "POP-Demo"; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 34003225191DFC8300A7CA32 /* POPCGUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = POPCGUtils.h; sourceTree = ""; }; 41 | 34003226191DFC8300A7CA32 /* POPCGUtils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = POPCGUtils.mm; sourceTree = ""; }; 42 | 34A67E2019114B9A00CCDA78 /* POP-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "POP-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 34A67E2319114B9A00CCDA78 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 44 | 34A67E2519114B9A00CCDA78 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 45 | 34A67E2719114B9A00CCDA78 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 46 | 34A67E2B19114B9A00CCDA78 /* POP-Demo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "POP-Demo-Info.plist"; sourceTree = ""; }; 47 | 34A67E2D19114B9A00CCDA78 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 48 | 34A67E2F19114B9A00CCDA78 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 49 | 34A67E3119114B9A00CCDA78 /* POP-Demo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "POP-Demo-Prefix.pch"; sourceTree = ""; }; 50 | 34A67E3219114B9A00CCDA78 /* MCAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MCAppDelegate.h; sourceTree = ""; }; 51 | 34A67E3319114B9A00CCDA78 /* MCAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MCAppDelegate.m; sourceTree = ""; }; 52 | 34A67E3619114B9A00CCDA78 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 34A67E3819114B9A00CCDA78 /* MCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MCViewController.h; sourceTree = ""; }; 54 | 34A67E3919114B9A00CCDA78 /* MCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MCViewController.m; sourceTree = ""; }; 55 | 34A67E3B19114B9A00CCDA78 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 56 | 34A67E4119114B9A00CCDA78 /* POP-DemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "POP-DemoTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 34A67E4219114B9A00CCDA78 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 58 | 34A67E4A19114B9A00CCDA78 /* POP-DemoTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "POP-DemoTests-Info.plist"; sourceTree = ""; }; 59 | 34A67E4C19114B9A00CCDA78 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 60 | 34A67E4E19114B9A00CCDA78 /* POP_DemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = POP_DemoTests.m; sourceTree = ""; }; 61 | 4F768501D0B147139C73F6F0 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 9E3818A01A124A8100D39B84 /* MCSequenceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MCSequenceController.h; sourceTree = ""; }; 63 | 9E3818A11A124A8100D39B84 /* MCSequenceController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MCSequenceController.m; sourceTree = ""; }; 64 | CFB40BA96BCEFC22DA35A58A /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 65 | D0D137EBAEA8C5097E6E2B2B /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 66 | /* End PBXFileReference section */ 67 | 68 | /* Begin PBXFrameworksBuildPhase section */ 69 | 34A67E1D19114B9A00CCDA78 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | 34A67E2619114B9A00CCDA78 /* CoreGraphics.framework in Frameworks */, 74 | 34A67E2819114B9A00CCDA78 /* UIKit.framework in Frameworks */, 75 | 34A67E2419114B9A00CCDA78 /* Foundation.framework in Frameworks */, 76 | F292894CD432482195635D85 /* libPods.a in Frameworks */, 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | 34A67E3E19114B9A00CCDA78 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | 34A67E4319114B9A00CCDA78 /* XCTest.framework in Frameworks */, 85 | 34A67E4519114B9A00CCDA78 /* UIKit.framework in Frameworks */, 86 | 34A67E4419114B9A00CCDA78 /* Foundation.framework in Frameworks */, 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | /* End PBXFrameworksBuildPhase section */ 91 | 92 | /* Begin PBXGroup section */ 93 | 0816E1C07822E5C28E9847A4 /* Pods */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | D0D137EBAEA8C5097E6E2B2B /* Pods.debug.xcconfig */, 97 | CFB40BA96BCEFC22DA35A58A /* Pods.release.xcconfig */, 98 | ); 99 | name = Pods; 100 | sourceTree = ""; 101 | }; 102 | 34A67E1719114B9A00CCDA78 = { 103 | isa = PBXGroup; 104 | children = ( 105 | 34A67E2919114B9A00CCDA78 /* POP-Demo */, 106 | 34A67E4819114B9A00CCDA78 /* POP-DemoTests */, 107 | 34A67E2219114B9A00CCDA78 /* Frameworks */, 108 | 34A67E2119114B9A00CCDA78 /* Products */, 109 | 0816E1C07822E5C28E9847A4 /* Pods */, 110 | ); 111 | sourceTree = ""; 112 | }; 113 | 34A67E2119114B9A00CCDA78 /* Products */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 34A67E2019114B9A00CCDA78 /* POP-Demo.app */, 117 | 34A67E4119114B9A00CCDA78 /* POP-DemoTests.xctest */, 118 | ); 119 | name = Products; 120 | sourceTree = ""; 121 | }; 122 | 34A67E2219114B9A00CCDA78 /* Frameworks */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 34A67E2319114B9A00CCDA78 /* Foundation.framework */, 126 | 34A67E2519114B9A00CCDA78 /* CoreGraphics.framework */, 127 | 34A67E2719114B9A00CCDA78 /* UIKit.framework */, 128 | 34A67E4219114B9A00CCDA78 /* XCTest.framework */, 129 | 4F768501D0B147139C73F6F0 /* libPods.a */, 130 | ); 131 | name = Frameworks; 132 | sourceTree = ""; 133 | }; 134 | 34A67E2919114B9A00CCDA78 /* POP-Demo */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 34A67E3219114B9A00CCDA78 /* MCAppDelegate.h */, 138 | 34A67E3319114B9A00CCDA78 /* MCAppDelegate.m */, 139 | 34A67E3519114B9A00CCDA78 /* Main.storyboard */, 140 | 34A67E3819114B9A00CCDA78 /* MCViewController.h */, 141 | 34A67E3919114B9A00CCDA78 /* MCViewController.m */, 142 | 9E3818A01A124A8100D39B84 /* MCSequenceController.h */, 143 | 9E3818A11A124A8100D39B84 /* MCSequenceController.m */, 144 | 34003225191DFC8300A7CA32 /* POPCGUtils.h */, 145 | 34003226191DFC8300A7CA32 /* POPCGUtils.mm */, 146 | 34A67E3B19114B9A00CCDA78 /* Images.xcassets */, 147 | 34A67E2A19114B9A00CCDA78 /* Supporting Files */, 148 | ); 149 | path = "POP-Demo"; 150 | sourceTree = ""; 151 | }; 152 | 34A67E2A19114B9A00CCDA78 /* Supporting Files */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 34A67E2B19114B9A00CCDA78 /* POP-Demo-Info.plist */, 156 | 34A67E2C19114B9A00CCDA78 /* InfoPlist.strings */, 157 | 34A67E2F19114B9A00CCDA78 /* main.m */, 158 | 34A67E3119114B9A00CCDA78 /* POP-Demo-Prefix.pch */, 159 | ); 160 | name = "Supporting Files"; 161 | sourceTree = ""; 162 | }; 163 | 34A67E4819114B9A00CCDA78 /* POP-DemoTests */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 34A67E4E19114B9A00CCDA78 /* POP_DemoTests.m */, 167 | 34A67E4919114B9A00CCDA78 /* Supporting Files */, 168 | ); 169 | path = "POP-DemoTests"; 170 | sourceTree = ""; 171 | }; 172 | 34A67E4919114B9A00CCDA78 /* Supporting Files */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 34A67E4A19114B9A00CCDA78 /* POP-DemoTests-Info.plist */, 176 | 34A67E4B19114B9A00CCDA78 /* InfoPlist.strings */, 177 | ); 178 | name = "Supporting Files"; 179 | sourceTree = ""; 180 | }; 181 | /* End PBXGroup section */ 182 | 183 | /* Begin PBXNativeTarget section */ 184 | 34A67E1F19114B9A00CCDA78 /* POP-Demo */ = { 185 | isa = PBXNativeTarget; 186 | buildConfigurationList = 34A67E5219114B9A00CCDA78 /* Build configuration list for PBXNativeTarget "POP-Demo" */; 187 | buildPhases = ( 188 | 7CBC3CD26DC34A459C11B9D0 /* Check Pods Manifest.lock */, 189 | 34A67E1C19114B9A00CCDA78 /* Sources */, 190 | 34A67E1D19114B9A00CCDA78 /* Frameworks */, 191 | 34A67E1E19114B9A00CCDA78 /* Resources */, 192 | 2FBD1E351F7E49DC812D703B /* Copy Pods Resources */, 193 | ); 194 | buildRules = ( 195 | ); 196 | dependencies = ( 197 | ); 198 | name = "POP-Demo"; 199 | productName = "POP-Demo"; 200 | productReference = 34A67E2019114B9A00CCDA78 /* POP-Demo.app */; 201 | productType = "com.apple.product-type.application"; 202 | }; 203 | 34A67E4019114B9A00CCDA78 /* POP-DemoTests */ = { 204 | isa = PBXNativeTarget; 205 | buildConfigurationList = 34A67E5519114B9A00CCDA78 /* Build configuration list for PBXNativeTarget "POP-DemoTests" */; 206 | buildPhases = ( 207 | 34A67E3D19114B9A00CCDA78 /* Sources */, 208 | 34A67E3E19114B9A00CCDA78 /* Frameworks */, 209 | 34A67E3F19114B9A00CCDA78 /* Resources */, 210 | ); 211 | buildRules = ( 212 | ); 213 | dependencies = ( 214 | 34A67E4719114B9A00CCDA78 /* PBXTargetDependency */, 215 | ); 216 | name = "POP-DemoTests"; 217 | productName = "POP-DemoTests"; 218 | productReference = 34A67E4119114B9A00CCDA78 /* POP-DemoTests.xctest */; 219 | productType = "com.apple.product-type.bundle.unit-test"; 220 | }; 221 | /* End PBXNativeTarget section */ 222 | 223 | /* Begin PBXProject section */ 224 | 34A67E1819114B9A00CCDA78 /* Project object */ = { 225 | isa = PBXProject; 226 | attributes = { 227 | CLASSPREFIX = MC; 228 | LastUpgradeCheck = 0510; 229 | ORGANIZATIONNAME = "Matthew Cheok"; 230 | TargetAttributes = { 231 | 34A67E4019114B9A00CCDA78 = { 232 | TestTargetID = 34A67E1F19114B9A00CCDA78; 233 | }; 234 | }; 235 | }; 236 | buildConfigurationList = 34A67E1B19114B9A00CCDA78 /* Build configuration list for PBXProject "POP-Demo" */; 237 | compatibilityVersion = "Xcode 3.2"; 238 | developmentRegion = English; 239 | hasScannedForEncodings = 0; 240 | knownRegions = ( 241 | en, 242 | Base, 243 | ); 244 | mainGroup = 34A67E1719114B9A00CCDA78; 245 | productRefGroup = 34A67E2119114B9A00CCDA78 /* Products */; 246 | projectDirPath = ""; 247 | projectRoot = ""; 248 | targets = ( 249 | 34A67E1F19114B9A00CCDA78 /* POP-Demo */, 250 | 34A67E4019114B9A00CCDA78 /* POP-DemoTests */, 251 | ); 252 | }; 253 | /* End PBXProject section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | 34A67E1E19114B9A00CCDA78 /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 34A67E3C19114B9A00CCDA78 /* Images.xcassets in Resources */, 261 | 34A67E2E19114B9A00CCDA78 /* InfoPlist.strings in Resources */, 262 | 34A67E3719114B9A00CCDA78 /* Main.storyboard in Resources */, 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | 34A67E3F19114B9A00CCDA78 /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | 34A67E4D19114B9A00CCDA78 /* InfoPlist.strings in Resources */, 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | /* End PBXResourcesBuildPhase section */ 275 | 276 | /* Begin PBXShellScriptBuildPhase section */ 277 | 2FBD1E351F7E49DC812D703B /* Copy Pods Resources */ = { 278 | isa = PBXShellScriptBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | ); 282 | inputPaths = ( 283 | ); 284 | name = "Copy Pods Resources"; 285 | outputPaths = ( 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | shellPath = /bin/sh; 289 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 290 | showEnvVarsInLog = 0; 291 | }; 292 | 7CBC3CD26DC34A459C11B9D0 /* Check Pods Manifest.lock */ = { 293 | isa = PBXShellScriptBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | ); 297 | inputPaths = ( 298 | ); 299 | name = "Check Pods Manifest.lock"; 300 | outputPaths = ( 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | shellPath = /bin/sh; 304 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 305 | showEnvVarsInLog = 0; 306 | }; 307 | /* End PBXShellScriptBuildPhase section */ 308 | 309 | /* Begin PBXSourcesBuildPhase section */ 310 | 34A67E1C19114B9A00CCDA78 /* Sources */ = { 311 | isa = PBXSourcesBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | 34A67E3419114B9A00CCDA78 /* MCAppDelegate.m in Sources */, 315 | 34A67E3A19114B9A00CCDA78 /* MCViewController.m in Sources */, 316 | 9E3818A21A124A8100D39B84 /* MCSequenceController.m in Sources */, 317 | 34A67E3019114B9A00CCDA78 /* main.m in Sources */, 318 | 34003227191DFC8300A7CA32 /* POPCGUtils.mm in Sources */, 319 | ); 320 | runOnlyForDeploymentPostprocessing = 0; 321 | }; 322 | 34A67E3D19114B9A00CCDA78 /* Sources */ = { 323 | isa = PBXSourcesBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | 34A67E4F19114B9A00CCDA78 /* POP_DemoTests.m in Sources */, 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | /* End PBXSourcesBuildPhase section */ 331 | 332 | /* Begin PBXTargetDependency section */ 333 | 34A67E4719114B9A00CCDA78 /* PBXTargetDependency */ = { 334 | isa = PBXTargetDependency; 335 | target = 34A67E1F19114B9A00CCDA78 /* POP-Demo */; 336 | targetProxy = 34A67E4619114B9A00CCDA78 /* PBXContainerItemProxy */; 337 | }; 338 | /* End PBXTargetDependency section */ 339 | 340 | /* Begin PBXVariantGroup section */ 341 | 34A67E2C19114B9A00CCDA78 /* InfoPlist.strings */ = { 342 | isa = PBXVariantGroup; 343 | children = ( 344 | 34A67E2D19114B9A00CCDA78 /* en */, 345 | ); 346 | name = InfoPlist.strings; 347 | sourceTree = ""; 348 | }; 349 | 34A67E3519114B9A00CCDA78 /* Main.storyboard */ = { 350 | isa = PBXVariantGroup; 351 | children = ( 352 | 34A67E3619114B9A00CCDA78 /* Base */, 353 | ); 354 | name = Main.storyboard; 355 | sourceTree = ""; 356 | }; 357 | 34A67E4B19114B9A00CCDA78 /* InfoPlist.strings */ = { 358 | isa = PBXVariantGroup; 359 | children = ( 360 | 34A67E4C19114B9A00CCDA78 /* en */, 361 | ); 362 | name = InfoPlist.strings; 363 | sourceTree = ""; 364 | }; 365 | /* End PBXVariantGroup section */ 366 | 367 | /* Begin XCBuildConfiguration section */ 368 | 34A67E5019114B9A00CCDA78 /* Debug */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 373 | CLANG_CXX_LIBRARY = "libc++"; 374 | CLANG_ENABLE_MODULES = YES; 375 | CLANG_ENABLE_OBJC_ARC = YES; 376 | CLANG_WARN_BOOL_CONVERSION = YES; 377 | CLANG_WARN_CONSTANT_CONVERSION = YES; 378 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 379 | CLANG_WARN_EMPTY_BODY = YES; 380 | CLANG_WARN_ENUM_CONVERSION = YES; 381 | CLANG_WARN_INT_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 384 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 385 | COPY_PHASE_STRIP = NO; 386 | GCC_C_LANGUAGE_STANDARD = gnu99; 387 | GCC_DYNAMIC_NO_PIC = NO; 388 | GCC_OPTIMIZATION_LEVEL = 0; 389 | GCC_PREPROCESSOR_DEFINITIONS = ( 390 | "DEBUG=1", 391 | "$(inherited)", 392 | ); 393 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 394 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 395 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 396 | GCC_WARN_UNDECLARED_SELECTOR = YES; 397 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 398 | GCC_WARN_UNUSED_FUNCTION = YES; 399 | GCC_WARN_UNUSED_VARIABLE = YES; 400 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 401 | ONLY_ACTIVE_ARCH = YES; 402 | SDKROOT = iphoneos; 403 | }; 404 | name = Debug; 405 | }; 406 | 34A67E5119114B9A00CCDA78 /* Release */ = { 407 | isa = XCBuildConfiguration; 408 | buildSettings = { 409 | ALWAYS_SEARCH_USER_PATHS = NO; 410 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 411 | CLANG_CXX_LIBRARY = "libc++"; 412 | CLANG_ENABLE_MODULES = YES; 413 | CLANG_ENABLE_OBJC_ARC = YES; 414 | CLANG_WARN_BOOL_CONVERSION = YES; 415 | CLANG_WARN_CONSTANT_CONVERSION = YES; 416 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 417 | CLANG_WARN_EMPTY_BODY = YES; 418 | CLANG_WARN_ENUM_CONVERSION = YES; 419 | CLANG_WARN_INT_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 422 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 423 | COPY_PHASE_STRIP = YES; 424 | ENABLE_NS_ASSERTIONS = NO; 425 | GCC_C_LANGUAGE_STANDARD = gnu99; 426 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 427 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 428 | GCC_WARN_UNDECLARED_SELECTOR = YES; 429 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 430 | GCC_WARN_UNUSED_FUNCTION = YES; 431 | GCC_WARN_UNUSED_VARIABLE = YES; 432 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 433 | SDKROOT = iphoneos; 434 | VALIDATE_PRODUCT = YES; 435 | }; 436 | name = Release; 437 | }; 438 | 34A67E5319114B9A00CCDA78 /* Debug */ = { 439 | isa = XCBuildConfiguration; 440 | baseConfigurationReference = D0D137EBAEA8C5097E6E2B2B /* Pods.debug.xcconfig */; 441 | buildSettings = { 442 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 443 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 444 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 445 | GCC_PREFIX_HEADER = "POP-Demo/POP-Demo-Prefix.pch"; 446 | INFOPLIST_FILE = "POP-Demo/POP-Demo-Info.plist"; 447 | PRODUCT_NAME = "$(TARGET_NAME)"; 448 | WRAPPER_EXTENSION = app; 449 | }; 450 | name = Debug; 451 | }; 452 | 34A67E5419114B9A00CCDA78 /* Release */ = { 453 | isa = XCBuildConfiguration; 454 | baseConfigurationReference = CFB40BA96BCEFC22DA35A58A /* Pods.release.xcconfig */; 455 | buildSettings = { 456 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 457 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 458 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 459 | GCC_PREFIX_HEADER = "POP-Demo/POP-Demo-Prefix.pch"; 460 | INFOPLIST_FILE = "POP-Demo/POP-Demo-Info.plist"; 461 | PRODUCT_NAME = "$(TARGET_NAME)"; 462 | WRAPPER_EXTENSION = app; 463 | }; 464 | name = Release; 465 | }; 466 | 34A67E5619114B9A00CCDA78 /* Debug */ = { 467 | isa = XCBuildConfiguration; 468 | baseConfigurationReference = D0D137EBAEA8C5097E6E2B2B /* Pods.debug.xcconfig */; 469 | buildSettings = { 470 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/POP-Demo.app/POP-Demo"; 471 | FRAMEWORK_SEARCH_PATHS = ( 472 | "$(SDKROOT)/Developer/Library/Frameworks", 473 | "$(inherited)", 474 | "$(DEVELOPER_FRAMEWORKS_DIR)", 475 | ); 476 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 477 | GCC_PREFIX_HEADER = "POP-Demo/POP-Demo-Prefix.pch"; 478 | GCC_PREPROCESSOR_DEFINITIONS = ( 479 | "DEBUG=1", 480 | "$(inherited)", 481 | ); 482 | INFOPLIST_FILE = "POP-DemoTests/POP-DemoTests-Info.plist"; 483 | PRODUCT_NAME = "$(TARGET_NAME)"; 484 | TEST_HOST = "$(BUNDLE_LOADER)"; 485 | WRAPPER_EXTENSION = xctest; 486 | }; 487 | name = Debug; 488 | }; 489 | 34A67E5719114B9A00CCDA78 /* Release */ = { 490 | isa = XCBuildConfiguration; 491 | baseConfigurationReference = CFB40BA96BCEFC22DA35A58A /* Pods.release.xcconfig */; 492 | buildSettings = { 493 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/POP-Demo.app/POP-Demo"; 494 | FRAMEWORK_SEARCH_PATHS = ( 495 | "$(SDKROOT)/Developer/Library/Frameworks", 496 | "$(inherited)", 497 | "$(DEVELOPER_FRAMEWORKS_DIR)", 498 | ); 499 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 500 | GCC_PREFIX_HEADER = "POP-Demo/POP-Demo-Prefix.pch"; 501 | INFOPLIST_FILE = "POP-DemoTests/POP-DemoTests-Info.plist"; 502 | PRODUCT_NAME = "$(TARGET_NAME)"; 503 | TEST_HOST = "$(BUNDLE_LOADER)"; 504 | WRAPPER_EXTENSION = xctest; 505 | }; 506 | name = Release; 507 | }; 508 | /* End XCBuildConfiguration section */ 509 | 510 | /* Begin XCConfigurationList section */ 511 | 34A67E1B19114B9A00CCDA78 /* Build configuration list for PBXProject "POP-Demo" */ = { 512 | isa = XCConfigurationList; 513 | buildConfigurations = ( 514 | 34A67E5019114B9A00CCDA78 /* Debug */, 515 | 34A67E5119114B9A00CCDA78 /* Release */, 516 | ); 517 | defaultConfigurationIsVisible = 0; 518 | defaultConfigurationName = Release; 519 | }; 520 | 34A67E5219114B9A00CCDA78 /* Build configuration list for PBXNativeTarget "POP-Demo" */ = { 521 | isa = XCConfigurationList; 522 | buildConfigurations = ( 523 | 34A67E5319114B9A00CCDA78 /* Debug */, 524 | 34A67E5419114B9A00CCDA78 /* Release */, 525 | ); 526 | defaultConfigurationIsVisible = 0; 527 | defaultConfigurationName = Release; 528 | }; 529 | 34A67E5519114B9A00CCDA78 /* Build configuration list for PBXNativeTarget "POP-DemoTests" */ = { 530 | isa = XCConfigurationList; 531 | buildConfigurations = ( 532 | 34A67E5619114B9A00CCDA78 /* Debug */, 533 | 34A67E5719114B9A00CCDA78 /* Release */, 534 | ); 535 | defaultConfigurationIsVisible = 0; 536 | defaultConfigurationName = Release; 537 | }; 538 | /* End XCConfigurationList section */ 539 | }; 540 | rootObject = 34A67E1819114B9A00CCDA78 /* Project object */; 541 | } 542 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/MCAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCAppDelegate.h 3 | // POP-Demo 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MCAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/MCAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCAppDelegate.m 3 | // POP-Demo 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCAppDelegate.h" 10 | 11 | @implementation MCAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/MCSequenceController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCSequenceController.h 3 | // POP-Demo 4 | // 5 | // Created by Matthew Cheok on 11/11/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MCSequenceController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/MCSequenceController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCSequenceController.m 3 | // POP-Demo 4 | // 5 | // Created by Matthew Cheok on 11/11/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCSequenceController.h" 10 | 11 | static NSUInteger const kNumberOfCircles = 18; 12 | static CGFloat const kCircleRadius = 50; 13 | static CGFloat const kCircleSize = 16; 14 | 15 | @interface MCSequenceController () 16 | 17 | @property (nonatomic, strong) NSArray *circles; 18 | 19 | @end 20 | 21 | @implementation MCSequenceController 22 | 23 | - (BOOL)prefersStatusBarHidden { 24 | return YES; 25 | } 26 | 27 | - (IBAction)handleTap:(id)sender { 28 | CGFloat angleIncrement = M_PI * 2 / kNumberOfCircles; 29 | CGPoint center = CGPointMake(CGRectGetWidth(self.view.bounds) / 2, CGRectGetHeight(self.view.bounds) / 2); 30 | 31 | NSArray *circles = self.circles; 32 | [circles sequenceWithInterval:0.1 animations:^(UIView *circle, NSInteger index){ 33 | CGPoint position = center; 34 | position.x += kCircleRadius * sin(angleIncrement * index); 35 | position.y -= kCircleRadius * cos(angleIncrement * index); 36 | 37 | circle.spring.center = position; 38 | circle.spring.alpha = 1; 39 | circle.spring.scaleXY = CGPointMake(1, 1); 40 | } completion:^(BOOL finished){ 41 | [circles sequenceWithInterval:0 animations:^(UIView *circle, NSInteger index){ 42 | CGPoint position = center; 43 | position.x += 2 * kCircleRadius * sin(angleIncrement * index); 44 | position.y -= 2 * kCircleRadius * cos(angleIncrement * index); 45 | 46 | circle.spring.center = position; 47 | } completion:^(BOOL finished){ 48 | [circles sequenceWithInterval:0 animations:^(UIView *circle, NSInteger index){ 49 | CGPoint position = center; 50 | position.x += 2 * kCircleRadius * sin(angleIncrement * (index-1)); 51 | position.y -= 2 * kCircleRadius * cos(angleIncrement * (index-1)); 52 | 53 | circle.spring.center = position; 54 | } completion:^(BOOL finished){ 55 | [circles sequenceWithInterval:0 animations:^(UIView *circle, NSInteger index){ 56 | CGPoint position = center; 57 | position.x += 2 * kCircleRadius * sin(angleIncrement * index); 58 | position.y -= 2 * kCircleRadius * cos(angleIncrement * index); 59 | 60 | circle.spring.center = position; 61 | } completion:^(BOOL finished){ 62 | [circles sequenceWithInterval:0.1 animations:^(UIView *circle, NSInteger index){ 63 | circle.spring.center = center; 64 | circle.spring.alpha = 0; 65 | circle.spring.scaleXY = CGPointMake(0.5, 0.5); 66 | } completion:nil]; 67 | }]; 68 | }]; 69 | }]; 70 | }]; 71 | } 72 | 73 | - (void)viewDidLoad { 74 | [super viewDidLoad]; 75 | // Do any additional setup after loading the view. 76 | 77 | CGPoint center = CGPointMake(CGRectGetWidth(self.view.bounds) / 2, CGRectGetHeight(self.view.bounds) / 2); 78 | 79 | NSMutableArray *circles = [NSMutableArray array]; 80 | 81 | for (int i = 0; i < kNumberOfCircles; i++) { 82 | UIView *circle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kCircleSize, kCircleSize)]; 83 | circle.backgroundColor = [UIColor colorWithRed:0.945 green:0.439 blue:0.416 alpha:1]; 84 | circle.layer.cornerRadius = kCircleSize / 2; 85 | circle.center = center; 86 | circle.alpha = 0; 87 | circle.scaleXY = CGPointMake(0.5, 0.5); 88 | 89 | [self.view addSubview:circle]; 90 | [circles addObject:circle]; 91 | } 92 | 93 | self.circles = [circles copy]; 94 | } 95 | 96 | - (void)didReceiveMemoryWarning { 97 | [super didReceiveMemoryWarning]; 98 | // Dispose of any resources that can be recreated. 99 | } 100 | 101 | /* 102 | #pragma mark - Navigation 103 | 104 | // In a storyboard-based application, you will often want to do a little preparation before navigation 105 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 106 | // Get the new view controller using [segue destinationViewController]. 107 | // Pass the selected object to the new view controller. 108 | } 109 | */ 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/MCViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MCViewController.h 3 | // POP-Demo 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MCViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/MCViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MCViewController.m 3 | // POP-Demo 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import "MCViewController.h" 10 | 11 | typedef NS_ENUM (NSInteger, MCControllerAnimationType) { 12 | MCControllerAnimationTypeSpring = 0, 13 | MCControllerAnimationTypeDecay, 14 | MCControllerAnimationTypeBasic, 15 | MCControllerAnimationTypeComplex 16 | }; 17 | 18 | #import "POPCGUtils.h" 19 | 20 | @interface MCViewController () 21 | 22 | @property (assign, nonatomic) MCControllerAnimationType type; 23 | @property (weak, nonatomic) IBOutlet UIView *boxView; 24 | @property (weak, nonatomic) IBOutlet UILabel *messageLabel; 25 | 26 | @end 27 | 28 | @implementation MCViewController 29 | 30 | - (UIColor *)greatColor { 31 | switch (self.type) { 32 | case MCControllerAnimationTypeSpring: 33 | return [UIColor colorWithRed:1.0f green:0.22f blue:0.22f alpha:1.0f]; 34 | 35 | case MCControllerAnimationTypeDecay: 36 | return [UIColor colorWithRed:1.0f green:0.79f blue:0.28f alpha:1.0f]; 37 | 38 | case MCControllerAnimationTypeBasic: 39 | return [UIColor colorWithRed:0.27f green:0.85f blue:0.46f alpha:1.0f]; 40 | 41 | case MCControllerAnimationTypeComplex: 42 | return [UIColor colorWithRed:0.18f green:0.67f blue:0.84f alpha:1.0f]; 43 | 44 | default: 45 | return [UIColor whiteColor]; 46 | } 47 | } 48 | 49 | - (IBAction)typeChanged:(UISegmentedControl *)segmentedControl { 50 | self.type = segmentedControl.selectedSegmentIndex; 51 | 52 | // move box to center 53 | CGPoint viewCenter = CGPointMake(CGRectGetMidX(self.view.bounds), 54 | CGRectGetMidY(self.view.bounds)); 55 | 56 | self.boxView.springBounciness = 4; 57 | self.boxView.springSpeed = 12; 58 | self.boxView.spring.center = viewCenter; 59 | 60 | 61 | switch (self.type) { 62 | case MCControllerAnimationTypeSpring: 63 | self.title = @"Spring Animation"; 64 | break; 65 | 66 | case MCControllerAnimationTypeDecay: 67 | self.title = @"Decay Animation"; 68 | break; 69 | 70 | case MCControllerAnimationTypeBasic: 71 | self.title = @"Basic Animation"; 72 | break; 73 | 74 | case MCControllerAnimationTypeComplex: 75 | self.title = @"Complex Animation"; 76 | break; 77 | 78 | default: 79 | self.title = @"No Animation"; 80 | break; 81 | } 82 | 83 | UIColor *selectedColor = [self greatColor]; 84 | self.navigationController.navigationBar.easeInEaseOut.barTintColor = selectedColor; 85 | self.boxView.easeInEaseOut.backgroundColor = selectedColor; 86 | 87 | [NSObject animate:^{ 88 | self.messageLabel.spring.textColor = selectedColor; 89 | } completion:^(BOOL finished) { 90 | self.messageLabel.spring.textColor = [UIColor blackColor]; 91 | }]; 92 | } 93 | 94 | - (IBAction)handlePan:(UIPanGestureRecognizer *)pan { 95 | switch (pan.state) { 96 | case UIGestureRecognizerStateBegan: 97 | case UIGestureRecognizerStateChanged: { 98 | CGPoint translation = [pan translationInView:self.boxView]; 99 | 100 | CGPoint center = self.boxView.center; 101 | center.x += translation.x; 102 | center.y += translation.y; 103 | self.boxView.center = center; 104 | 105 | [pan setTranslation:CGPointZero inView:self.boxView]; 106 | break; 107 | } 108 | 109 | case UIGestureRecognizerStateEnded: 110 | case UIGestureRecognizerStateCancelled: { 111 | CGPoint viewCenter = CGPointMake(CGRectGetMidX(self.view.bounds), 112 | CGRectGetMidY(self.view.bounds)); 113 | 114 | switch (self.type) { 115 | case MCControllerAnimationTypeSpring: { 116 | self.boxView.velocity.center = [pan velocityInView:self.boxView]; 117 | self.boxView.pop_delegate = self; 118 | self.boxView.springBounciness = 20; 119 | self.boxView.springSpeed = 20; 120 | self.boxView.spring.center = viewCenter; 121 | break; 122 | } 123 | 124 | case MCControllerAnimationTypeDecay: { 125 | self.boxView.velocity.center = [pan velocityInView:self.boxView]; 126 | [self.boxView.decay center]; 127 | break; 128 | } 129 | 130 | case MCControllerAnimationTypeBasic: { 131 | self.boxView.duration = 1; 132 | self.boxView.easeInEaseOut.center = viewCenter; 133 | break; 134 | } 135 | 136 | case MCControllerAnimationTypeComplex: { 137 | self.boxView.springBounciness = 4; 138 | self.boxView.springSpeed = 12; 139 | self.boxView.layer.springBounciness = 1; 140 | self.boxView.layer.springSpeed = 1; 141 | 142 | UIColor *selectedColor = [self greatColor]; 143 | [NSObject animate: ^{ 144 | self.boxView.spring.scaleXY = CGPointMake(2, 2); 145 | self.boxView.spring.backgroundColor = [[UIColor purpleColor] colorWithAlphaComponent:0.5]; 146 | } completion: ^(BOOL finished) { 147 | [NSObject animate: ^{ 148 | self.boxView.layer.spring.rotation = M_PI * 2; 149 | } completion: ^(BOOL finished) { 150 | NSLog(@"finished? %d", finished); 151 | self.boxView.spring.scaleXY = CGPointMake(1, 1); 152 | self.boxView.spring.backgroundColor = selectedColor; 153 | self.boxView.spring.center = viewCenter; 154 | }]; 155 | // [self.boxView.layer.stop rotation]; 156 | }]; 157 | break; 158 | } 159 | 160 | default: 161 | break; 162 | } 163 | 164 | break; 165 | } 166 | 167 | default: 168 | break; 169 | } 170 | } 171 | 172 | - (void)viewDidLoad { 173 | [super viewDidLoad]; 174 | // Do any additional setup after loading the view, typically from a nib. 175 | 176 | #ifdef MCANIMATE_SHORTHAND 177 | NSLog(@"shorthand enabled"); 178 | #else 179 | NSLog(@"shorthand disabled"); 180 | #endif 181 | 182 | // declare custom property 183 | [UILabel registerAnimatablePropertyWithName:@"textColor" readBlock:^(UILabel *label, CGFloat values[]) { 184 | POPUIColorGetRGBAComponents(label.textColor, values); 185 | } writeBlock:^(UILabel *label, const CGFloat values[]) { 186 | label.textColor = POPUIColorRGBACreate(values); 187 | } threshold:0.01]; 188 | 189 | self.navigationController.navigationBar.barTintColor = [UIColor whiteColor]; 190 | self.boxView.backgroundColor = [UIColor whiteColor]; 191 | 192 | [self typeChanged:nil]; 193 | } 194 | 195 | - (void)didReceiveMemoryWarning { 196 | [super didReceiveMemoryWarning]; 197 | // Dispose of any resources that can be recreated. 198 | } 199 | 200 | - (void)pop_animationDidStop:(POPAnimation *)anim finished:(BOOL)finished { 201 | NSLog(@"delegate stop"); 202 | } 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/POP-Demo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.matthewcheok.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/POP-Demo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | 17 | #define MCANIMATE_SHORTHAND 18 | #import 19 | #endif 20 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/POPCGUtils.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2014-present, Facebook, Inc. 3 | All rights reserved. 4 | 5 | This source code is licensed under the BSD-style license found in the 6 | LICENSE file in the root directory of this source tree. An additional grant 7 | of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | #import "POPDefines.h" 12 | 13 | #if TARGET_OS_IPHONE 14 | @class UIColor; 15 | #endif 16 | 17 | POP_EXTERN_C_BEGIN 18 | 19 | NS_INLINE CGPoint values_to_point(const CGFloat values[]) 20 | { 21 | return CGPointMake(values[0], values[1]); 22 | } 23 | 24 | NS_INLINE CGSize values_to_size(const CGFloat values[]) 25 | { 26 | return CGSizeMake(values[0], values[1]); 27 | } 28 | 29 | NS_INLINE CGRect values_to_rect(const CGFloat values[]) 30 | { 31 | return CGRectMake(values[0], values[1], values[2], values[3]); 32 | } 33 | 34 | NS_INLINE void values_from_point(CGFloat values[], CGPoint p) 35 | { 36 | values[0] = p.x; 37 | values[1] = p.y; 38 | } 39 | 40 | NS_INLINE void values_from_size(CGFloat values[], CGSize s) 41 | { 42 | values[0] = s.width; 43 | values[1] = s.height; 44 | } 45 | 46 | NS_INLINE void values_from_rect(CGFloat values[], CGRect r) 47 | { 48 | values[0] = r.origin.x; 49 | values[1] = r.origin.y; 50 | values[2] = r.size.width; 51 | values[3] = r.size.height; 52 | } 53 | 54 | /** 55 | Takes a CGColorRef and converts it into RGBA components, if necessary. 56 | */ 57 | extern void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]); 58 | 59 | /** 60 | Takes RGBA components and returns a CGColorRef. 61 | */ 62 | extern CGColorRef POPCGColorRGBACreate(const CGFloat components[]) CF_RETURNS_RETAINED; 63 | 64 | /** 65 | Takes a color reference and returns a CGColor. 66 | */ 67 | extern CGColorRef POPCGColorWithColor(id color); 68 | 69 | #if TARGET_OS_IPHONE 70 | 71 | /** 72 | Takes a UIColor and converts it into RGBA components, if necessary. 73 | */ 74 | extern void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]); 75 | 76 | /** 77 | Takes RGBA components and returns a UIColor. 78 | */ 79 | extern UIColor *POPUIColorRGBACreate(const CGFloat components[]) NS_RETURNS_RETAINED; 80 | 81 | #endif 82 | 83 | POP_EXTERN_C_END 84 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/POPCGUtils.mm: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (c) 2014-present, Facebook, Inc. 3 | All rights reserved. 4 | 5 | This source code is licensed under the BSD-style license found in the 6 | LICENSE file in the root directory of this source tree. An additional grant 7 | of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "POPCGUtils.h" 11 | 12 | #if TARGET_OS_IPHONE 13 | #import 14 | #else 15 | #import 16 | #endif 17 | 18 | void POPCGColorGetRGBAComponents(CGColorRef color, CGFloat components[]) 19 | { 20 | if (!color) { 21 | #if TARGET_OS_IPHONE 22 | color = [UIColor clearColor].CGColor; 23 | #else 24 | color = [NSColor clearColor].CGColor; 25 | #endif 26 | } 27 | 28 | const CGFloat *colors = CGColorGetComponents(color); 29 | size_t count = CGColorGetNumberOfComponents(color); 30 | 31 | if (4 == count) { 32 | // RGB colorspace 33 | components[0] = colors[0]; 34 | components[1] = colors[1]; 35 | components[2] = colors[2]; 36 | components[3] = colors[3]; 37 | } else if (2 == count) { 38 | // Grey colorspace 39 | components[0] = components[1] = components[2] = colors[0]; 40 | components[3] = colors[1]; 41 | } else { 42 | // Use CI to convert 43 | CIColor *ciColor = [CIColor colorWithCGColor:color]; 44 | components[0] = ciColor.red; 45 | components[1] = ciColor.green; 46 | components[2] = ciColor.blue; 47 | components[3] = ciColor.alpha; 48 | } 49 | } 50 | 51 | CGColorRef POPCGColorRGBACreate(const CGFloat components[]) 52 | { 53 | #if TARGET_OS_IPHONE 54 | CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 55 | CGColorRef color = CGColorCreate(space, components); 56 | CGColorSpaceRelease(space); 57 | return color; 58 | #else 59 | return CGColorCreateGenericRGB(components[0], components[1], components[2], components[3]); 60 | #endif 61 | } 62 | 63 | CGColorRef POPCGColorWithColor(id color) 64 | { 65 | if (CFGetTypeID((__bridge CFTypeRef)color) == CGColorGetTypeID()) { 66 | return ((__bridge CGColorRef)color); 67 | } 68 | #if TARGET_OS_IPHONE 69 | else if ([color isKindOfClass:[UIColor class]]) { 70 | return [color CGColor]; 71 | } 72 | #else 73 | else if ([color isKindOfClass:[NSColor class]]) { 74 | return [color CGColor]; 75 | } 76 | #endif 77 | return nil; 78 | } 79 | 80 | #if TARGET_OS_IPHONE 81 | 82 | void POPUIColorGetRGBAComponents(UIColor *color, CGFloat components[]) 83 | { 84 | return POPCGColorGetRGBAComponents(color.CGColor, components); 85 | } 86 | 87 | UIColor *POPUIColorRGBACreate(const CGFloat components[]) 88 | { 89 | CGColorRef colorRef = POPCGColorRGBACreate(components); 90 | UIColor *color = [[UIColor alloc] initWithCGColor:colorRef]; 91 | CGColorRelease(colorRef); 92 | return color; 93 | } 94 | 95 | #endif 96 | 97 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /POP-Demo/POP-Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // POP-Demo 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "MCAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([MCAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /POP-Demo/POP-DemoTests/POP-DemoTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.matthewcheok.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /POP-Demo/POP-DemoTests/POP_DemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // POP_DemoTests.m 3 | // POP-DemoTests 4 | // 5 | // Created by Matthew Cheok on 30/4/14. 6 | // Copyright (c) 2014 Matthew Cheok. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface POP_DemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation POP_DemoTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /POP-Demo/POP-DemoTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /POP-Demo/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :ios, "7.0" 3 | 4 | pod 'POP+MCAnimate', :path => '../' 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | POP+MCAnimate ![License MIT](https://go-shields.herokuapp.com/license-MIT-blue.png) 2 | ============= 3 | 4 | [![Badge w/ Version](https://cocoapod-badges.herokuapp.com/v/POP+MCAnimate/badge.png)](https://github.com/matthewcheok/POP-MCAnimate) 5 | [![Badge w/ Platform](https://cocoapod-badges.herokuapp.com/p/POP+MCAnimate/badge.svg)](https://github.com/matthewcheok/POP-MCAnimate) 6 | 7 | Concise syntax for the [Pop](https://github.com/facebook/pop) animation framework. For more on the motivation behind this experiment, read this [blog post](http://blog.matthewcheok.com/making-your-animations-pop/). 8 | 9 | ## Installation 10 | 11 | Add the following to your [CocoaPods](http://cocoapods.org/) Podfile 12 | ```ruby 13 | pod 'POP+MCAnimate', '~> 2.0' 14 | ``` 15 | 16 | or clone as a git submodule, 17 | 18 | or just copy files in the ```POP+MCAnimate``` folder into your project. 19 | 20 | ## Using POP+MCAnimate 21 | 22 | **Breaking change:** Methods and properties have been prefixed with *pop_*. See section on shorthand syntax below. 23 | 24 | Replace this: 25 | ```objc 26 | POPSpringAnimation *animation = [self.boxView pop_animationForKey:@"bounds"]; 27 | if (!animation) { 28 | animation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewBounds]; 29 | } 30 | 31 | animation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)]; 32 | [self.boxView pop_addAnimation:animation forKey:@"bounds"]; 33 | ``` 34 | 35 | With this:* 36 | ```objc 37 | self.boxView.spring.bounds = CGRectMake(0, 0, 200, 200); 38 | ``` 39 | 40 | ### Spring Animation 41 | 42 | You can configure `velocity`, `springBounciness` and `springSpeed`. 43 | ```objc 44 | self.boxView.velocity.center = [pan velocityInView:self.boxView]; 45 | self.boxView.springBounciness = 20; 46 | self.boxView.springSpeed = 20; 47 | self.boxView.spring.center = viewCenter; 48 | ``` 49 | 50 | ### Decay Animation 51 | 52 | You can configure `velocity` and `decayDeceleration`. 53 | ```objc 54 | self.boxView.velocity.center = [pan velocityInView:self.boxView]; 55 | self.boxView.decayDeceleration = 0.998; 56 | [self.boxView.decay center]; 57 | ``` 58 | 59 | ### Basic Animation 60 | 61 | You can configure `duration` and use different timing functions by swapping out `easeInEaseOut` for `easeIn`, `easeOut` or `linear`. 62 | ```objc 63 | self.boxView.duration = 1; 64 | self.boxView.easeInEaseOut.center = viewCenter; 65 | ``` 66 | 67 | ### Grouping and Completion Handlers 68 | 69 | Block-based methods are provided on `NSObject` similar to UIKit block-based animation methods. The `completion` block waits for all animations in the `animate` block to complete before executing. 70 | ```objc 71 | [NSObject animate:^{ 72 | self.boxView.spring.alpha = 0.5; 73 | self.boxView.spring.bounds = CGRectMake(0, 0, 200, 200); 74 | self.boxView.spring.backgroundColor = [UIColor blueColor]; 75 | } completion:^(BOOL finished) { 76 | self.boxView.alpha = 1; 77 | self.boxView.spring.bounds = CGRectMake(0, 0, 100, 100); 78 | self.boxView.spring.backgroundColor = [UIColor redColor]; 79 | self.boxView.spring.center = viewCenter; 80 | }]; 81 | ``` 82 | 83 | If you need to stop animations mid-way, use the stop proxy: 84 | ```objc 85 | [self.boxView.stop bounds]; 86 | ``` 87 | 88 | The `finished` flag in the completion handler will return `NO` if any of the animations in the group were stopped before completion. 89 | 90 | ## Staggering Animations 91 | 92 | Big thanks to @borndangerous and @bradjasper for their suggestion on `beginTime`. Great idea from @borndangerous on using sequences. 93 | 94 | Set the `beginTime` property before any animations to stagger the animations by the said amount: 95 | ```objc 96 | circle.beginTime = CACurrentMediaTime() + 0.1 97 | circle.spring.alpha = 1; 98 | circle.spring.scaleXY = CGPointMake(1, 1); 99 | ``` 100 | 101 | Once `beginTime` is set, it will persist until removed (by setting to 0), so all animations following that will be affected (which is probably what you want.) 102 | 103 | If you work with `NSArrays`, it's even easier using the `-sequenceWithInterval:animations:completion:` method: 104 | ```objc 105 | [circles sequenceWithInterval:0.1 animations:^(UIView *circle, NSInteger index){ 106 | circle.spring.center = position; 107 | circle.spring.alpha = 1; 108 | circle.spring.scaleXY = CGPointMake(1, 1); 109 | } completion:^(BOOL finished){ 110 | }]; 111 | ``` 112 | 113 | ## Custom Properties 114 | 115 | You can make any property animatable by first declaring it: 116 | ```objc 117 | [UILabel registerAnimatablePropertyWithName:@"textColor" readBlock:^(UILabel *label, CGFloat values[]) { 118 | POPUIColorGetRGBAComponents(label.textColor, values); 119 | } writeBlock:^(UILabel *label, const CGFloat values[]) { 120 | label.textColor = POPUIColorRGBACreate(values); 121 | } threshold:0.01]; 122 | ``` 123 | 124 | You do this by providing a read block, write block and threshold to tell Pop how to get and set numerical values on your property and the smallest increment to change it by. Later, just animate as usual: 125 | ```objc 126 | self.messageLabel.spring.textColor = [UIColor blackColor]; 127 | ``` 128 | 129 | ## Shorthand* 130 | 131 | The above examples require the use of **shorthand** so you can drop the *pop_* prefix from methods and properties. Just include the following in your pre-compiled header file after importing **UIKit**: 132 | 133 | ```objc 134 | #define MCANIMATE_SHORTHAND 135 | #import 136 | ``` 137 | 138 | ## Remarks 139 | 140 | The list of supported properties are: 141 | - **CALayer** (and subclasses) 142 | - backgroundColor 143 | - bounds 144 | - opacity 145 | - position 146 | - zPosition 147 | - *pop_*positionX 148 | - *pop_*positionY 149 | - *pop_*rotation 150 | - *pop_*rotationX 151 | - *pop_*rotationY 152 | - *pop_*scaleX 153 | - *pop_*scaleY 154 | - *pop_*scaleXY 155 | - *pop_*translationX 156 | - *pop_*translationXY 157 | - *pop_*translationY 158 | - *pop_*translationZ 159 | - *pop_*size 160 | 161 | 162 | - **CAShapeLayer** 163 | - strokeColor 164 | - strokeStart 165 | - strokeEnd 166 | 167 | 168 | - **NSLayoutConstraint** 169 | - constant 170 | 171 | 172 | - **UIView** (and subclasses) 173 | - alpha 174 | - backgroundColor 175 | - bounds 176 | - center 177 | - frame 178 | - *pop_*scaleX 179 | - *pop_*scaleY 180 | - *pop_*scaleXY 181 | 182 | 183 | - **UIScrollView** (and subclasses) 184 | - contentOffset 185 | - contentSize 186 | 187 | 188 | ## License 189 | 190 | POP+MCAnimate is under the MIT license. 191 | --------------------------------------------------------------------------------