diff --git a/.gitignore b/.gitignore index 296d47a..267121b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.xcuserstate *.xcuserdatad -.DS_Store \ No newline at end of file +.DS_Store +*.xccheckout diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..96f0d19 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ + +language: objective-c + +before_install: +- gem install cocoapods + +script: +- pod repo update --silent +- pod lib lint +- cd example +- xctool -project PRTween.xcodeproj -scheme 'PRTween' -configuration Release -sdk iphonesimulator -arch i386 build diff --git a/PRTween.podspec b/PRTween.podspec new file mode 100644 index 0000000..c52425e --- /dev/null +++ b/PRTween.podspec @@ -0,0 +1,19 @@ + +Pod::Spec.new do |s| + + s.name = 'PRTween' + s.version = '0.1.0' + s.license = 'BSD' + s.summary = 'PRTween is a lightweight tweening library built for iOS.' + s.homepage = 'https://github.com/dominikhofmann/PRTween' + s.author = { 'Dominik Hofmann' => '' } + + s.source = { :git => "https://github.com/PRTween/PRTween.git", :tag => "#{s.version}" } + + s.description = 'While Apple has done an incredible job with UIView Animations and Core Animation, there are sometimes cases that are difficult to get around. PRTween is a great alternative if you\'d like to: Animate a property Core Animation won\'t allow you to Ensure that [someView layoutSubviews] is respected during an animation Tween arbitrary numerical values, such as sound volume, scroll position, a counter, or many others Define your timing curve as a function rather than a bezier with control points PRTween aims to be as simple as possible without sacrificing flexibility. In many cases, an animation may be as simple as: [PRTween tween:someView property:@"alpha" from:1 to:0 duration:3]; In order to promote simplicity, PRTween can be used as a drop-in replacement for most animations in your app. This means that in the case displayed above, the end result is identical to writing a UIView animation yourself.' + + s.platform = :ios + s.requires_arc = true + s.source_files = 'lib/*.{h,m}' + +end diff --git a/example/PRTween.xcodeproj/project.pbxproj b/example/PRTween.xcodeproj/project.pbxproj index c3f124d..795c5ff 100644 --- a/example/PRTween.xcodeproj/project.pbxproj +++ b/example/PRTween.xcodeproj/project.pbxproj @@ -149,7 +149,7 @@ B25002B1139558F700670D11 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0440; + LastUpgradeCheck = 0500; ORGANIZATIONNAME = Jetsetter; }; buildConfigurationList = B25002B4139558F700670D11 /* Build configuration list for PBXProject "PRTween" */; @@ -228,7 +228,6 @@ B25002D9139558F700670D11 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_OPTIMIZATION_LEVEL = 0; @@ -238,6 +237,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 4.3; + ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; }; @@ -246,7 +246,6 @@ B25002DA139558F700670D11 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_VERSION = com.apple.compilers.llvmgcc42; diff --git a/example/PRTween.xcodeproj/xcshareddata/xcschemes/PRTween.xcscheme b/example/PRTween.xcodeproj/xcshareddata/xcschemes/PRTween.xcscheme index 6e73091..994f5c0 100644 --- a/example/PRTween.xcodeproj/xcshareddata/xcschemes/PRTween.xcscheme +++ b/example/PRTween.xcodeproj/xcshareddata/xcschemes/PRTween.xcscheme @@ -1,6 +1,6 @@ diff --git a/example/PRTweenExampleViewController.m b/example/PRTweenExampleViewController.m index b1f5e70..71b4d9c 100644 --- a/example/PRTweenExampleViewController.m +++ b/example/PRTweenExampleViewController.m @@ -75,8 +75,9 @@ - (IBAction)verboseTapped { - (IBAction)blockTapped { activeTweenOperation = [[PRTween sharedInstance] addTweenPeriod:[PRTweenPeriod periodWithStartValue:0 endValue:904 duration:1.5] updateBlock:^(PRTweenPeriod *period) { testView.frame = CGRectMake(0, period.tweenedValue, 100, 100); - } completionBlock:^(void) { - NSLog(@"Completed tween"); + } completionBlock:^(BOOL finished) { + if (finished) NSLog(@"Completed tween"); + else NSLog(@"Tween preempted before completion."); }]; } diff --git a/lib/PRTween.h b/lib/PRTween.h index 069baf5..09e9663 100755 --- a/lib/PRTween.h +++ b/lib/PRTween.h @@ -1,15 +1,24 @@ - -#import - +#import #import "PRTweenTimingFunctions.h" +#import "PRTweenLinearDamping.h" typedef CGFloat(*PRTweenTimingFunction)(CGFloat, CGFloat, CGFloat, CGFloat); + #if NS_BLOCKS_AVAILABLE @class PRTweenPeriod; + typedef void (^PRTweenUpdateBlock)(PRTweenPeriod *period); -typedef void (^PRTweenCompleteBlock)(); + +typedef void (^PRTweenCompleteBlock)(BOOL finished); + #endif +enum { + PRTweenHasTweenedValueObserver = 1 << 0, + PRTweenHasTweenedLerpObserver = 1 << 1, +}; +typedef NSUInteger PRTweenHasTweenedObserverOptions; + @interface PRTweenPeriod : NSObject { CGFloat duration; CGFloat delay; @@ -19,20 +28,28 @@ typedef void (^PRTweenCompleteBlock)(); CGFloat tweenedValue; } -@property (nonatomic) CGFloat startValue; -@property (nonatomic) CGFloat endValue; -@property (nonatomic) CGFloat tweenedValue; -@property (nonatomic) CGFloat duration; -@property (nonatomic) CGFloat delay; -@property (nonatomic) CGFloat startOffset; +@property(nonatomic) CGFloat startValue; +@property(nonatomic) CGFloat endValue; +@property(nonatomic) CGFloat tweenedValue; +@property(nonatomic) CGFloat duration; +@property(nonatomic) CGFloat delay; +@property(nonatomic) CGFloat startOffset; + ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration; -+ (id)periodWithStartValue:(CGFloat)aStartValue endValue:(CGFloat)anEndValue duration:(CGFloat)duration; ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay; @end @protocol PRTweenLerpPeriod -- (NSValue*)tweenedValueForProgress:(CGFloat)progress; +- (NSValue *)tweenedValueForProgress:(CGFloat)progress; + - (void)setProgress:(CGFloat)progress; @end @@ -43,146 +60,385 @@ typedef void (^PRTweenCompleteBlock)(); NSValue *tweenedLerp; } -@property (nonatomic, copy) NSValue *startLerp; -@property (nonatomic, copy) NSValue *endLerp; -@property (nonatomic, copy) NSValue *tweenedLerp; +@property(nonatomic, copy) NSValue *startLerp; +@property(nonatomic, copy) NSValue *endLerp; +@property(nonatomic, copy) NSValue *tweenedLerp; -+ (id)periodWithStartValue:(NSValue*)aStartValue endValue:(NSValue*)anEndValue duration:(CGFloat)duration; ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration; ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay; @end @interface PRTweenCGPointLerpPeriod : PRTweenLerpPeriod -+ (id)periodWithStartCGPoint:(CGPoint)aStartPoint endCGPoint:(CGPoint)anEndPoint duration:(CGFloat)duration; ++ (id)periodWithStartCGPoint:(CGPoint)aStartPoint + endCGPoint:(CGPoint)anEndPoint + duration:(CGFloat)duration; + - (CGPoint)startCGPoint; + - (CGPoint)tweenedCGPoint; + - (CGPoint)endCGPoint; @end @interface PRTweenCGRectLerpPeriod : PRTweenLerpPeriod -+ (id)periodWithStartCGRect:(CGRect)aStartRect endCGRect:(CGRect)anEndRect duration:(CGFloat)duration; ++ (id)periodWithStartCGRect:(CGRect)aStartRect + endCGRect:(CGRect)anEndRect + duration:(CGFloat)duration; + - (CGRect)startCGRect; + - (CGRect)tweenedCGRect; + - (CGRect)endCGRect; @end @interface PRTweenCGSizeLerpPeriod : PRTweenLerpPeriod -+ (id)periodWithStartCGSize:(CGSize)aStartSize endCGSize:(CGSize)anEndSize duration:(CGFloat)duration; ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration; + ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration + delay:(CGFloat)delay; + - (CGSize)startCGSize; + - (CGSize)tweenedCGSize; + - (CGSize)endCGSize; @end @interface PRTweenOperation : NSObject { PRTweenPeriod *period; - NSObject *target; - SEL updateSelector; - SEL completeSelector; + NSObject *target; + SEL updateSelector; + SEL completeSelector; PRTweenTimingFunction timingFunction; - + CGFloat *boundRef; SEL boundGetter; SEL boundSetter; - + BOOL override; - + BOOL wasPreempted; + + PRTweenHasTweenedObserverOptions observers; + #if NS_BLOCKS_AVAILABLE - PRTweenUpdateBlock updateBlock; - PRTweenCompleteBlock completeBlock; + PRTweenUpdateBlock updateBlock; + PRTweenCompleteBlock completeBlock; #endif - - @private + +@private BOOL canUseBuiltAnimation; } -@property (nonatomic, retain) PRTweenPeriod *period; -@property (nonatomic, retain) NSObject *target; -@property (nonatomic) SEL updateSelector; -@property (nonatomic) SEL completeSelector; -@property (nonatomic, assign) PRTweenTimingFunction timingFunction; +@property(nonatomic, retain) PRTweenPeriod *period; +@property(nonatomic, retain) NSObject *target; +@property(nonatomic) SEL updateSelector; +@property(nonatomic) SEL completeSelector; +@property(nonatomic, assign) PRTweenTimingFunction timingFunction; #if NS_BLOCKS_AVAILABLE -@property (nonatomic, copy) PRTweenUpdateBlock updateBlock; -@property (nonatomic, copy) PRTweenCompleteBlock completeBlock; +@property(nonatomic, copy) PRTweenUpdateBlock updateBlock; +@property(nonatomic, copy) PRTweenCompleteBlock completeBlock; #endif -@property (nonatomic, assign) CGFloat *boundRef; -@property (nonatomic, retain) id boundObject; -@property (nonatomic) SEL boundGetter; -@property (nonatomic) SEL boundSetter; -@property (nonatomic) BOOL override; +@property(nonatomic, assign) CGFloat *boundRef; +@property(nonatomic, retain) id boundObject; +@property(nonatomic) SEL boundGetter; +@property(nonatomic) SEL boundSetter; +@property(nonatomic) BOOL override; +@property(nonatomic) BOOL wasPreempted; + +@property(nonatomic) PRTweenHasTweenedObserverOptions observers; @end @interface PRTweenCGPointLerp : NSObject -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector; -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector; -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration; + #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + #endif @end @interface PRTweenCGRectLerp : NSObject -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector; -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector; -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration; + #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + #endif @end @interface PRTweenCGSizeLerp : NSObject -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector; -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector; -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target completeSelector:(SEL)selector; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration; + #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + +//+ (PRTweenOperation *)lerp:(id)object +// property:(NSString *)property +// from:(CGSize)from +// to:(CGSize)to +// duration:(CGFloat)duration +// delay:(CGFloat)delay +// timingFunction:(PRTweenTimingFunction)timingFunction +// updateBlock:(PRTweenUpdateBlock)updateBlock +// completeBlock:(PRTweenCompleteBlock)completeBlock; + #endif @end @interface PRTween : NSObject { NSMutableArray *tweenOperations; NSMutableArray *expiredTweenOperations; - NSTimer *timer; + NSTimer *timer; CGFloat timeOffset; - + PRTweenTimingFunction defaultTimingFunction; - BOOL useBuiltInAnimationsWhenPossible; + BOOL useBuiltInAnimationsWhenPossible; } -@property (nonatomic, readonly) CGFloat timeOffset; -@property (nonatomic, assign) PRTweenTimingFunction defaultTimingFunction; -@property (nonatomic, assign) BOOL useBuiltInAnimationsWhenPossible; +@property(nonatomic, readonly) CGFloat timeOffset; +@property(nonatomic, assign) PRTweenTimingFunction defaultTimingFunction; +@property(nonatomic, assign) BOOL useBuiltInAnimationsWhenPossible; + (PRTween *)sharedInstance; -+ (PRTweenOperation *)tween:(id)object property:(NSString*)property from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject*)target completeSelector:(SEL)selector; - -+ (PRTweenOperation *)tween:(CGFloat*)ref from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject*)target completeSelector:(SEL)selector; - -+ (PRTweenOperation *)tween:(id)object property:(NSString*)property from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration; - -+ (PRTweenOperation *)tween:(CGFloat*)ref from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration; - -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property period:(PRTweenLerpPeriod *)period timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector; - -- (PRTweenOperation *)addTweenOperation:(PRTweenOperation*)operation; -- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period target:(NSObject *)target selector:(SEL)selector; -- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period target:(NSObject *)target selector:(SEL)selector timingFunction:(PRTweenTimingFunction)timingFunction; -- (void)removeTweenOperation:(PRTweenOperation*)tweenOperation; ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector; + +- (PRTweenOperation *)addTweenOperation:(PRTweenOperation *)operation; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + target:(NSObject *)target + selector:(SEL)selector; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + target:(NSObject *)target + selector:(SEL)selector + timingFunction:(PRTweenTimingFunction)timingFunction; + +- (void)removeTweenOperation:(PRTweenOperation *)tweenOperation; + +- (void)removeAllTweenOperations; #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)tween:(id)object property:(NSString*)property from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; - -+ (PRTweenOperation *)tween:(CGFloat*)ref from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; -+ (PRTweenOperation *)lerp:(id)object property:(NSString*)property period:(PRTweenLerpPeriod *)period timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock; ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(PRTweenUpdateBlock)updateBlock + completionBlock:(PRTweenCompleteBlock)completeBlock; + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(PRTweenUpdateBlock)updateBlock + completionBlock:(PRTweenCompleteBlock)completionBlock + timingFunction:(PRTweenTimingFunction)timingFunction; -- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period updateBlock:(PRTweenUpdateBlock)updateBlock completionBlock:(PRTweenCompleteBlock)completeBlock; -- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period updateBlock:(PRTweenUpdateBlock)updateBlock completionBlock:(PRTweenCompleteBlock)completionBlock timingFunction:(PRTweenTimingFunction)timingFunction; #endif @end diff --git a/lib/PRTween.m b/lib/PRTween.m index e8b39af..b654374 100755 --- a/lib/PRTween.m +++ b/lib/PRTween.m @@ -11,14 +11,33 @@ @implementation PRTweenPeriod @synthesize delay; @synthesize startOffset; -+ (id)periodWithStartValue:(CGFloat)aStartValue endValue:(CGFloat)anEndValue duration:(CGFloat)duration { ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration { + PRTweenPeriod *period = [PRTweenPeriod new]; - + period.startValue = period.tweenedValue = aStartValue; - period.endValue = anEndValue; - period.duration = duration; - period.startOffset = [[PRTween sharedInstance] timeOffset]; - + period.endValue = anEndValue; + period.duration = duration; + period.startOffset = [[PRTween sharedInstance] timeOffset]; + + return period; +} + ++ (id)periodWithStartValue:(CGFloat)aStartValue + endValue:(CGFloat)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay { + + PRTweenPeriod *period = [PRTweenPeriod new]; + + period.startValue = period.tweenedValue = aStartValue; + period.endValue = anEndValue; + period.duration = duration; + period.delay = delay; + period.startOffset = [[PRTween sharedInstance] timeOffset]; + return period; } @@ -29,14 +48,33 @@ @implementation PRTweenLerpPeriod @synthesize endLerp; @synthesize tweenedLerp; -+ (id)periodWithStartValue:(NSValue*)aStartValue endValue:(NSValue*)anEndValue duration:(CGFloat)duration { ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration { + + PRTweenLerpPeriod *period = [[self class] new]; + period.startLerp = aStartValue; + period.tweenedLerp = aStartValue; + period.endLerp = anEndValue; + period.duration = duration; + period.startOffset = [[PRTween sharedInstance] timeOffset]; + + return period; +} + ++ (id)periodWithStartValue:(NSValue *)aStartValue + endValue:(NSValue *)anEndValue + duration:(CGFloat)duration + delay:(CGFloat)delay { + PRTweenLerpPeriod *period = [[self class] new]; - period.startLerp = aStartValue; + period.startLerp = aStartValue; period.tweenedLerp = aStartValue; - period.endLerp = anEndValue; - period.duration = duration; + period.endLerp = anEndValue; + period.duration = duration; + period.delay = delay; period.startOffset = [[PRTween sharedInstance] timeOffset]; - + return period; } @@ -44,23 +82,34 @@ + (id)periodWithStartValue:(NSValue*)aStartValue endValue:(NSValue*)anEndValue d @implementation PRTweenCGPointLerpPeriod -+ (id)periodWithStartCGPoint:(CGPoint)aStartPoint endCGPoint:(CGPoint)anEndPoint duration:(CGFloat)duration { ++ (id)periodWithStartCGPoint:(CGPoint)aStartPoint + endCGPoint:(CGPoint)anEndPoint + duration:(CGFloat)duration { + return [PRTweenCGPointLerpPeriod periodWithStartValue:[NSValue valueWithCGPoint:aStartPoint] endValue:[NSValue valueWithCGPoint:anEndPoint] duration:duration]; } -- (CGPoint)startCGPoint { return [self.startLerp CGPointValue]; } -- (CGPoint)tweenedCGPoint { return [self.tweenedLerp CGPointValue]; } -- (CGPoint)endCGPoint { return [self.endLerp CGPointValue]; } +- (CGPoint)startCGPoint { + return [self.startLerp CGPointValue]; +} -- (NSValue*)tweenedValueForProgress:(CGFloat)progress { - - CGPoint startPoint = self.startCGPoint; - CGPoint endPoint = self.endCGPoint; - CGPoint distance = CGPointMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y); +- (CGPoint)tweenedCGPoint { + return [self.tweenedLerp CGPointValue]; +} + +- (CGPoint)endCGPoint { + return [self.endLerp CGPointValue]; +} + +- (NSValue *)tweenedValueForProgress:(CGFloat)progress { + + CGPoint startPoint = self.startCGPoint; + CGPoint endPoint = self.endCGPoint; + CGPoint distance = CGPointMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y); CGPoint tweenedPoint = CGPointMake(startPoint.x + distance.x * progress, startPoint.y + distance.y * progress); - + return [NSValue valueWithCGPoint:tweenedPoint]; - + } - (void)setProgress:(CGFloat)progress { @@ -71,23 +120,34 @@ - (void)setProgress:(CGFloat)progress { @implementation PRTweenCGRectLerpPeriod -+ (id)periodWithStartCGRect:(CGRect)aStartRect endCGRect:(CGRect)anEndRect duration:(CGFloat)duration { ++ (id)periodWithStartCGRect:(CGRect)aStartRect + endCGRect:(CGRect)anEndRect + duration:(CGFloat)duration { + return [PRTweenCGRectLerpPeriod periodWithStartValue:[NSValue valueWithCGRect:aStartRect] endValue:[NSValue valueWithCGRect:anEndRect] duration:duration]; } -- (CGRect)startCGRect { return [self.startLerp CGRectValue]; } -- (CGRect)tweenedCGRect { return [self.tweenedLerp CGRectValue]; } -- (CGRect)endCGRect { return [self.endLerp CGRectValue]; } +- (CGRect)startCGRect { + return [self.startLerp CGRectValue]; +} + +- (CGRect)tweenedCGRect { + return [self.tweenedLerp CGRectValue]; +} + +- (CGRect)endCGRect { + return [self.endLerp CGRectValue]; +} - (NSValue *)tweenedValueForProgress:(CGFloat)progress { - - CGRect startRect = self.startCGRect; - CGRect endRect = self.endCGRect; - CGRect distance = CGRectMake(endRect.origin.x - startRect.origin.x, endRect.origin.y - startRect.origin.y, endRect.size.width - startRect.size.width, endRect.size.height - startRect.size.height); + + CGRect startRect = self.startCGRect; + CGRect endRect = self.endCGRect; + CGRect distance = CGRectMake(endRect.origin.x - startRect.origin.x, endRect.origin.y - startRect.origin.y, endRect.size.width - startRect.size.width, endRect.size.height - startRect.size.height); CGRect tweenedRect = CGRectMake(startRect.origin.x + distance.origin.x * progress, startRect.origin.y + distance.origin.y * progress, startRect.size.width + distance.size.width * progress, startRect.size.height + distance.size.height * progress); - + return [NSValue valueWithCGRect:tweenedRect]; - + } - (void)setProgress:(CGFloat)progress { @@ -98,22 +158,41 @@ - (void)setProgress:(CGFloat)progress { @implementation PRTweenCGSizeLerpPeriod -+ (id)periodWithStartCGSize:(CGSize)aStartSize endCGSize:(CGSize)anEndSize duration:(CGFloat)duration { ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration { + return [PRTweenCGRectLerpPeriod periodWithStartValue:[NSValue valueWithCGSize:aStartSize] endValue:[NSValue valueWithCGSize:anEndSize] duration:duration]; } -- (CGSize)startCGSize { return [self.startLerp CGSizeValue]; } -- (CGSize)tweenedCGSize { return [self.tweenedLerp CGSizeValue]; } -- (CGSize)endCGSize { return [self.endLerp CGSizeValue]; } ++ (id)periodWithStartCGSize:(CGSize)aStartSize + endCGSize:(CGSize)anEndSize + duration:(CGFloat)duration + delay:(CGFloat)delay { + + return [PRTweenCGRectLerpPeriod periodWithStartValue:[NSValue valueWithCGSize:aStartSize] endValue:[NSValue valueWithCGSize:anEndSize] duration:duration delay:delay]; +} + +- (CGSize)startCGSize { + return [self.startLerp CGSizeValue]; +} + +- (CGSize)tweenedCGSize { + return [self.tweenedLerp CGSizeValue]; +} + +- (CGSize)endCGSize { + return [self.endLerp CGSizeValue]; +} - (NSValue *)tweenedValueForProgress:(CGFloat)progress { - - CGSize startSize = self.startCGSize; - CGSize endSize = self.endCGSize; - CGSize distance = CGSizeMake(endSize.width - startSize.width, endSize.height - startSize.height); + + CGSize startSize = self.startCGSize; + CGSize endSize = self.endCGSize; + CGSize distance = CGSizeMake(endSize.width - startSize.width, endSize.height - startSize.height); CGSize tweenedSize = CGSizeMake(startSize.width + distance.width * progress, startSize.height + distance.height * progress); return [NSValue valueWithCGSize:tweenedSize]; - + } - (void)setProgress:(CGFloat)progress { @@ -123,7 +202,7 @@ - (void)setProgress:(CGFloat)progress { @end @interface PRTweenOperation () -@property (nonatomic) BOOL canUseBuiltAnimation; +@property(nonatomic) BOOL canUseBuiltAnimation; @end @implementation PRTweenOperation @@ -138,6 +217,8 @@ @implementation PRTweenOperation @synthesize boundSetter; @synthesize canUseBuiltAnimation; @synthesize override; +@synthesize wasPreempted; +@synthesize observers; #if NS_BLOCKS_AVAILABLE @synthesize updateBlock; @@ -148,108 +229,288 @@ @implementation PRTweenOperation @implementation PRTweenCGPointLerp -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector { - return [PRTween lerp:object property:property period:[PRTweenCGPointLerpPeriod periodWithStartCGPoint:from endCGPoint:to duration:duration] timingFunction:timingFunction target:target completeSelector:selector]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + return [PRTween lerp:object + property:property + period:[PRTweenCGPointLerpPeriod + periodWithStartCGPoint:from + endCGPoint:to + duration:duration] + timingFunction:timingFunction + target:target + completeSelector:selector]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector { ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + PRTweenCGPointLerpPeriod *period = [PRTweenCGPointLerpPeriod periodWithStartCGPoint:from endCGPoint:to duration:duration]; period.delay = delay; - return [PRTween lerp:object property:property period:period timingFunction:timingFunction target:target completeSelector:selector]; + + return [PRTween lerp:object + property:property + period:period + timingFunction:timingFunction + target:target + completeSelector:selector]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration { - return [PRTweenCGPointLerp lerp:object property:property from:from to:to duration:duration timingFunction:NULL target:nil completeSelector:NULL]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration { + + return [PRTweenCGPointLerp + lerp:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; } #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - return [PRTween lerp:object property:property period:[PRTweenCGPointLerpPeriod periodWithStartCGPoint:from endCGPoint:to duration:duration] timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + return [PRTween lerp:object + property:property + period:[PRTweenCGPointLerpPeriod + periodWithStartCGPoint:from + endCGPoint:to + duration:duration] + timingFunction:timingFunction + updateBlock:updateBlock + completeBlock:completeBlock]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGPoint)from to:(CGPoint)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGPoint)from + to:(CGPoint)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + PRTweenCGPointLerpPeriod *period = [PRTweenCGPointLerpPeriod periodWithStartCGPoint:from endCGPoint:to duration:duration]; [period setDelay:delay]; - + return [PRTween lerp:object property:property period:period timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; } + #endif @end @implementation PRTweenCGRectLerp -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector { - return [PRTween lerp:object property:property period:[PRTweenCGRectLerpPeriod periodWithStartCGRect:from endCGRect:to duration:duration] timingFunction:timingFunction target:target completeSelector:selector]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + return [PRTween lerp:object + property:property + period:[PRTweenCGRectLerpPeriod + periodWithStartCGRect:from + endCGRect:to + duration:duration] + timingFunction:timingFunction + target:target + completeSelector:selector]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector { - PRTweenCGRectLerpPeriod *period = [PRTweenCGRectLerpPeriod periodWithStartCGRect:from endCGRect:to duration:duration]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenCGRectLerpPeriod *period = [PRTweenCGRectLerpPeriod periodWithStartCGRect:from + endCGRect:to + duration:duration]; period.delay = delay; - return [PRTween lerp:object property:property period:period timingFunction:timingFunction target:target completeSelector:selector]; + return [PRTween lerp:object + property:property + period:period + timingFunction:timingFunction + target:target + completeSelector:selector]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration { - return [PRTweenCGRectLerp lerp:object property:property from:from to:to duration:duration timingFunction:NULL target:nil completeSelector:NULL]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration { + + return [PRTweenCGRectLerp lerp:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; } #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { return [PRTween lerp:object property:property period:[PRTweenCGRectLerpPeriod periodWithStartCGRect:from endCGRect:to duration:duration] timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGRect)from to:(CGRect)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGRect)from + to:(CGRect)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + PRTweenCGRectLerpPeriod *period = [PRTweenCGRectLerpPeriod periodWithStartCGRect:from endCGRect:to duration:duration]; [period setDelay:delay]; - + return [PRTween lerp:object property:property period:period timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; } + #endif @end @implementation PRTweenCGSizeLerp -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector { - return [PRTween lerp:object property:property period:[PRTweenCGSizeLerpPeriod periodWithStartCGSize:from endCGSize:to duration:duration] timingFunction:timingFunction target:target completeSelector:selector]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + return [PRTween lerp:object + property:property + period:[PRTweenCGSizeLerpPeriod + periodWithStartCGSize:from + endCGSize:to + duration:duration] + timingFunction:timingFunction + target:target + completeSelector:selector]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector { - PRTweenCGPointLerpPeriod *period = [PRTweenCGSizeLerpPeriod periodWithStartCGSize:from endCGSize:to duration:duration]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenCGPointLerpPeriod *period = [PRTweenCGSizeLerpPeriod periodWithStartCGSize:from + endCGSize:to + duration:duration]; period.delay = delay; - return [PRTween lerp:object property:property period:period timingFunction:timingFunction target:target completeSelector:selector]; + return [PRTween lerp:object + property:property + period:period + timingFunction:timingFunction + target:target + completeSelector:selector]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration { - return [PRTweenCGSizeLerp lerp:object property:property from:from to:to duration:duration timingFunction:NULL target:nil completeSelector:NULL]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration { + + return [PRTweenCGSizeLerp lerp:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; } #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - return [PRTween lerp:object property:property period:[PRTweenCGSizeLerpPeriod periodWithStartCGSize:from endCGSize:to duration:duration] timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; -} -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property from:(CGSize)from to:(CGSize)to duration:(CGFloat)duration delay:(CGFloat)delay timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - - PRTweenCGSizeLerpPeriod *period = [PRTweenCGSizeLerpPeriod periodWithStartCGSize:from endCGSize:to duration:duration]; - [period setDelay:delay]; - - return [PRTween lerp:object property:property period:period timingFunction:timingFunction updateBlock:updateBlock completeBlock:completeBlock]; ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + from:(CGSize)from + to:(CGSize)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + return [PRTween lerp:object + property:property + period:[PRTweenCGSizeLerpPeriod + periodWithStartCGSize:from + endCGSize:to + duration:duration] + timingFunction:timingFunction + updateBlock:updateBlock + completeBlock:completeBlock]; } + #endif @end @interface PRTween () + (SEL)setterFromProperty:(NSString *)property; + - (void)update; @end -static PRTween *instance = nil; +static PRTween *instance = nil; static NSArray *animationSelectorsForCoreAnimation = nil; -static NSArray *animationSelectorsForUIView = nil; +static NSArray *animationSelectorsForUIView = nil; @implementation PRTween @synthesize timeOffset; @@ -264,148 +525,316 @@ + (PRTween *)sharedInstance { return instance; } -+ (PRTweenOperation *)tween:(id)object property:(NSString*)property from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject*)target completeSelector:(SEL)selector { - - PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from endValue:to duration:duration]; ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; PRTweenOperation *operation = [PRTweenOperation new]; - operation.period = period; - operation.timingFunction = timingFunction; - operation.target = target; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; operation.completeSelector = selector; - operation.boundObject = object; - operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); - operation.boundSetter = [PRTween setterFromProperty:property]; - [operation addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" options:NSKeyValueObservingOptionNew context:NULL]; - + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; return operation; - + } -+ (PRTweenOperation *)tween:(CGFloat *)ref from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject*)target completeSelector:(SEL)selector { - - PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from endValue:to duration:duration]; ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; PRTweenOperation *operation = [PRTweenOperation new]; - operation.period = period; - operation.timingFunction = timingFunction; - operation.target = target; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; operation.completeSelector = selector; - operation.boundRef = ref; - [operation addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" options:NSKeyValueObservingOptionNew context:NULL]; - - [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; return operation; - + } -+ (PRTweenOperation *)tween:(id)object property:(NSString*)property from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration { - return [PRTween tween:object property:property from:from to:to duration:duration timingFunction:NULL target:nil completeSelector:NULL]; ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration + delay:delay]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; + operation.completeSelector = selector; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + } -+ (PRTweenOperation *)tween:(CGFloat *)ref from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration { - return [PRTween tween:ref from:from to:to duration:duration timingFunction:NULL target:nil completeSelector:NULL]; ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration { + + return [PRTween tween:object + property:property + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property period:(PRTweenLerpPeriod *)period timingFunction:(PRTweenTimingFunction)timingFunction target:(NSObject *)target completeSelector:(SEL)selector { - ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration { + + return [PRTween tween:ref + from:from + to:to + duration:duration + timingFunction:NULL target:nil completeSelector:NULL]; +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + target:(NSObject *)target + completeSelector:(SEL)selector { + //PRTweenPeriod *period = [PRTweenLerpPeriod periodWithStartValue:from endValue:to duration:duration]; PRTweenOperation *operation = [PRTweenOperation new]; - operation.period = period; - operation.timingFunction = timingFunction; - operation.target = target; + operation.period = period; + operation.timingFunction = timingFunction; + operation.target = target; operation.completeSelector = selector; - operation.boundObject = object; - operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); - operation.boundSetter = [PRTween setterFromProperty:property]; - [operation addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp" options:NSKeyValueObservingOptionNew context:NULL]; - - [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp" observerOptions:PRTweenHasTweenedLerpObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; return operation; - + } #if NS_BLOCKS_AVAILABLE -+ (PRTweenOperation *)tween:(id)object property:(NSString*)property from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - - PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from endValue:to duration:duration]; + ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; PRTweenOperation *operation = [PRTweenOperation new]; - operation.period = period; + operation.period = period; operation.timingFunction = timingFunction; - operation.updateBlock = updateBlock; - operation.completeBlock = completeBlock; - operation.boundObject = object; - operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); - operation.boundSetter = [PRTween setterFromProperty:property]; - [operation addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" options:NSKeyValueObservingOptionNew context:NULL]; - + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; return operation; - + } -+ (PRTweenOperation *)tween:(CGFloat *)ref from:(CGFloat)from to:(CGFloat)to duration:(CGFloat)duration timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - - PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from endValue:to duration:duration]; ++ (PRTweenOperation *)tween:(id)object + property:(NSString *)property + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration + delay:delay]; PRTweenOperation *operation = [PRTweenOperation new]; - operation.period = period; + operation.period = period; operation.timingFunction = timingFunction; - operation.updateBlock = updateBlock; - operation.completeBlock = completeBlock; - operation.boundRef = ref; - [operation addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" options:NSKeyValueObservingOptionNew context:NULL]; - + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; return operation; - + } -+ (PRTweenOperation *)lerp:(id)object property:(NSString *)property period:(PRTweenLerpPeriod *)period timingFunction:(PRTweenTimingFunction)timingFunction updateBlock:(PRTweenUpdateBlock)updateBlock completeBlock:(PRTweenCompleteBlock)completeBlock { - ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + ++ (PRTweenOperation *)tween:(CGFloat *)ref + from:(CGFloat)from + to:(CGFloat)to + duration:(CGFloat)duration + delay:(CGFloat)delay + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + + PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:from + endValue:to + duration:duration + delay:delay]; + PRTweenOperation *operation = [PRTweenOperation new]; + operation.period = period; + operation.timingFunction = timingFunction; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundRef = ref; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue" observerOptions:PRTweenHasTweenedValueObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + return operation; + +} + ++ (PRTweenOperation *)lerp:(id)object + property:(NSString *)property + period:(PRTweenLerpPeriod *)period + timingFunction:(PRTweenTimingFunction)timingFunction + updateBlock:(PRTweenUpdateBlock)updateBlock + completeBlock:(PRTweenCompleteBlock)completeBlock { + //PRTweenPeriod *period = [PRTweenLerpPeriod periodWithStartValue:from endValue:to duration:duration]; PRTweenOperation *operation = [PRTweenOperation new]; - operation.period = period; + operation.period = period; operation.timingFunction = timingFunction; - operation.updateBlock = updateBlock; - operation.completeBlock = completeBlock; - operation.boundObject = object; - operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); - operation.boundSetter = [PRTween setterFromProperty:property]; - [operation addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp" options:NSKeyValueObservingOptionNew context:NULL]; - - [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0]; + operation.updateBlock = updateBlock; + operation.completeBlock = completeBlock; + operation.boundObject = object; + operation.boundGetter = NSSelectorFromString([NSString stringWithFormat:@"%@", property]); + operation.boundSetter = [PRTween setterFromProperty:property]; + operation.wasPreempted = NO; + [self addObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp" observerOptions:PRTweenHasTweenedLerpObserver operation:operation]; + + [[PRTween sharedInstance] performSelector:@selector(addTweenOperation:) withObject:operation afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; return operation; - + } + #endif -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - - PRTweenOperation *operation = (PRTweenOperation*)object; - ++ (void)addObserver:(NSObject *)observer + forKeyPath:(NSString *)keyPath + observerOptions:(PRTweenHasTweenedObserverOptions)observerOptions + operation:(PRTweenOperation *)operation { + + [operation addObserver:observer forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL]; + operation.observers = operation.observers | observerOptions; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + + PRTweenOperation *operation = (PRTweenOperation *) object; + if ([operation.period isKindOfClass:[PRTweenLerpPeriod class]]) { - PRTweenLerpPeriod *lerpPeriod = (PRTweenLerpPeriod*)operation.period; - + PRTweenLerpPeriod *lerpPeriod = (PRTweenLerpPeriod *) operation.period; + NSUInteger bufferSize = 0; NSGetSizeAndAlignment([lerpPeriod.tweenedLerp objCType], &bufferSize, NULL); void *tweenedValue = malloc(bufferSize); [lerpPeriod.tweenedLerp getValue:tweenedValue]; - + if (operation.boundObject && [operation.boundObject respondsToSelector:operation.boundGetter] && [operation.boundObject respondsToSelector:operation.boundSetter]) { - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[operation.boundObject class] instanceMethodSignatureForSelector:operation.boundSetter]]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[operation.boundObject class] + instanceMethodSignatureForSelector:operation.boundSetter]]; [invocation setTarget:operation.boundObject]; [invocation setSelector:operation.boundSetter]; [invocation setArgument:tweenedValue atIndex:2]; [invocation invoke]; } - + free(tweenedValue); - + } else { - + CGFloat tweenedValue = operation.period.tweenedValue; - + if (operation.boundObject && [operation.boundObject respondsToSelector:operation.boundGetter] && [operation.boundObject respondsToSelector:operation.boundSetter]) { - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[operation.boundObject class] instanceMethodSignatureForSelector:operation.boundSetter]]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[operation.boundObject class] + instanceMethodSignatureForSelector:operation.boundSetter]]; [invocation setTarget:operation.boundObject]; [invocation setSelector:operation.boundSetter]; [invocation setArgument:&tweenedValue atIndex:2]; @@ -413,102 +842,104 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N } else if (operation.boundRef) { *operation.boundRef = tweenedValue; } - + } - + } - (id)init { self = [super init]; if (self != nil) { - tweenOperations = [[NSMutableArray alloc] init]; + tweenOperations = [[NSMutableArray alloc] init]; expiredTweenOperations = [[NSMutableArray alloc] init]; - timeOffset = 0; + timeOffset = 0; if (timer == nil) { timer = [NSTimer scheduledTimerWithTimeInterval:kPRTweenFramerate target:self selector:@selector(update) userInfo:nil repeats:YES]; + [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; } self.defaultTimingFunction = &PRTweenTimingFunctionQuadInOut; } return self; } -- (PRTweenOperation*)addTweenOperation:(PRTweenOperation*)operation { - +- (PRTweenOperation *)addTweenOperation:(PRTweenOperation *)operation { + if (useBuiltInAnimationsWhenPossible && !operation.override) { - + if (animationSelectorsForCoreAnimation == nil) { animationSelectorsForCoreAnimation = [[NSArray alloc] initWithObjects: - @"setBounds:", // CGRect - @"setPosition:", // CGPoint - @"setZPosition:", // CGFloat - @"setAnchorPoint:", // CGPoint - @"setAnchorPointZ:", // CGFloat - //@"setTransform:", // CATransform3D - //@"setSublayerTransform:", // CATransform3D - @"setFrame:", // CGRect - @"setContentsRect" // CGRect - @"setContentsScale:", // CGFloat - @"setContentsCenter:", // CGPoint - //@"setBackgroundColor:", // CGColorRef - @"setCornerRadius:", // CGFloat - @"setBorderWidth:", // CGFloat - @"setOpacity:", // CGFloat - //@"setShadowColor:", // CGColorRef - @"setShadowOpacity:", // CGFloat - @"setShadowOffset:", // CGSize - @"setShadowRadius:", // CGFloat - //@"setShadowPath:", - nil]; + @"setBounds:", // CGRect + @"setPosition:", // CGPoint + @"setZPosition:", // CGFloat + @"setAnchorPoint:", // CGPoint + @"setAnchorPointZ:", // CGFloat + //@"setTransform:", // CATransform3D + //@"setSublayerTransform:", // CATransform3D + @"setFrame:", // CGRect + @"setContentsRect" // CGRect + @"setContentsScale:", // CGFloat + @"setContentsCenter:", // CGPoint + //@"setBackgroundColor:", // CGColorRef + @"setCornerRadius:", // CGFloat + @"setBorderWidth:", // CGFloat + @"setOpacity:", // CGFloat + //@"setShadowColor:", // CGColorRef + @"setShadowOpacity:", // CGFloat + @"setShadowOffset:", // CGSize + @"setShadowRadius:", // CGFloat + //@"setShadowPath:", + nil]; } - + if (animationSelectorsForUIView == nil) { animationSelectorsForUIView = [[NSArray alloc] initWithObjects: - @"setFrame:", // CGRect - @"setBounds:", // CGRect - @"setCenter:", // CGPoint - @"setTransform:", // CGAffineTransform - @"setAlpha:", // CGFloat - //@"setBackgroundColor:", // UIColor - @"setContentStretch:", // CGRect - nil]; + @"setFrame:", // CGRect + @"setBounds:", // CGRect + @"setCenter:", // CGPoint + @"setTransform:", // CGAffineTransform + @"setAlpha:", // CGFloat + //@"setBackgroundColor:", // UIColor + @"setContentStretch:", // CGRect + nil]; } - + if (operation.boundSetter && operation.boundObject && !(operation.timingFunction == &PRTweenTimingFunctionCADefault || - operation.timingFunction == &PRTweenTimingFunctionCAEaseIn || - operation.timingFunction == &PRTweenTimingFunctionCAEaseOut || - operation.timingFunction == &PRTweenTimingFunctionCAEaseInOut || - operation.timingFunction == &PRTweenTimingFunctionCALinear || - operation.timingFunction == &PRTweenTimingFunctionUIViewEaseIn || - operation.timingFunction == &PRTweenTimingFunctionUIViewEaseOut || - operation.timingFunction == &PRTweenTimingFunctionUIViewEaseInOut || - operation.timingFunction == &PRTweenTimingFunctionUIViewLinear || - operation.timingFunction == NULL)) { + operation.timingFunction == &PRTweenTimingFunctionCAEaseIn || + operation.timingFunction == &PRTweenTimingFunctionCAEaseOut || + operation.timingFunction == &PRTweenTimingFunctionCAEaseInOut || + operation.timingFunction == &PRTweenTimingFunctionCALinear || + operation.timingFunction == &PRTweenTimingFunctionUIViewEaseIn || + operation.timingFunction == &PRTweenTimingFunctionUIViewEaseOut || + operation.timingFunction == &PRTweenTimingFunctionUIViewEaseInOut || + operation.timingFunction == &PRTweenTimingFunctionUIViewLinear || + operation.timingFunction == NULL)) { goto complete; } - - + + if (operation.boundSetter && operation.boundObject && [operation.boundObject isKindOfClass:[CALayer class]]) { for (NSString *selector in animationSelectorsForCoreAnimation) { NSString *setter = NSStringFromSelector(operation.boundSetter); if ([selector isEqualToString:setter]) { NSLog(@"Using Core Animation for %@", NSStringFromSelector(operation.boundSetter)); operation.canUseBuiltAnimation = YES; - - NSString *propertyUnformatted = [selector stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""]; - NSString *propertyFormatted = [[propertyUnformatted stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyUnformatted substringToIndex:1] lowercaseString]] substringToIndex:[propertyUnformatted length] - 1]; + + NSString *propertyUnformatted = [selector stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""]; + NSString *propertyFormatted = [[propertyUnformatted stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyUnformatted substringToIndex:1] + lowercaseString]] substringToIndex:[propertyUnformatted length] - 1]; //NSLog(@"%@", propertyFormatted); - CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:propertyFormatted]; + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:propertyFormatted]; animation.duration = operation.period.duration; - + if (![operation.period isKindOfClass:[PRTweenLerpPeriod class]] && ![operation.period conformsToProtocol:@protocol(PRTweenLerpPeriod)]) { animation.fromValue = [NSNumber numberWithFloat:operation.period.startValue]; - animation.toValue = [NSNumber numberWithFloat:operation.period.endValue]; + animation.toValue = [NSNumber numberWithFloat:operation.period.endValue]; } else { - PRTweenLerpPeriod *period = (PRTweenLerpPeriod*)operation.period; + PRTweenLerpPeriod *period = (PRTweenLerpPeriod *) operation.period; animation.fromValue = period.startLerp; - animation.toValue = period.endLerp; + animation.toValue = period.endLerp; } - + if (operation.timingFunction == &PRTweenTimingFunctionCAEaseIn) { animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]; } else if (operation.timingFunction == &PRTweenTimingFunctionCAEaseOut) { @@ -520,10 +951,10 @@ - (PRTweenOperation*)addTweenOperation:(PRTweenOperation*)operation { } else { animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]; } - + [operation.boundObject setValue:animation.toValue forKeyPath:propertyFormatted]; [operation.boundObject addAnimation:animation forKey:@"PRTweenCAAnimation"]; - + goto complete; } } @@ -533,123 +964,140 @@ - (PRTweenOperation*)addTweenOperation:(PRTweenOperation*)operation { if ([selector isEqualToString:setter]) { NSLog(@"Using UIView Animation for %@", NSStringFromSelector(operation.boundSetter)); operation.canUseBuiltAnimation = YES; - + NSString *propertyUnformatted = [selector stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""]; - NSString *propertyFormatted = [[propertyUnformatted stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyUnformatted substringToIndex:1] lowercaseString]] substringToIndex:[propertyUnformatted length] - 1]; - + NSString *propertyFormatted = [[propertyUnformatted stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyUnformatted substringToIndex:1] + lowercaseString]] substringToIndex:[propertyUnformatted length] - 1]; + NSValue *fromValue = nil; - NSValue *toValue = nil; - + NSValue *toValue = nil; + if (![operation.period isKindOfClass:[PRTweenLerpPeriod class]] && ![operation.period conformsToProtocol:@protocol(PRTweenLerpPeriod)]) { fromValue = [NSNumber numberWithFloat:operation.period.startValue]; - toValue = [NSNumber numberWithFloat:operation.period.endValue]; + toValue = [NSNumber numberWithFloat:operation.period.endValue]; } else { - PRTweenLerpPeriod *period = (PRTweenLerpPeriod*)operation.period; + PRTweenLerpPeriod *period = (PRTweenLerpPeriod *) operation.period; fromValue = period.startLerp; - toValue = period.endLerp; + toValue = period.endLerp; } - + [operation.boundObject setValue:fromValue forKeyPath:propertyFormatted]; [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:operation.period.duration]; - + if (operation.timingFunction == &PRTweenTimingFunctionUIViewEaseIn) { [UIView setAnimationCurve:UIViewAnimationCurveEaseIn]; } else if (operation.timingFunction == &PRTweenTimingFunctionUIViewEaseOut) { [UIView setAnimationCurve:UIViewAnimationCurveEaseOut]; } else if (operation.timingFunction == &PRTweenTimingFunctionUIViewEaseInOut) { - [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; + [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; } else if (operation.timingFunction == &PRTweenTimingFunctionUIViewLinear) { [UIView setAnimationCurve:UIViewAnimationCurveLinear]; } - + [operation.boundObject setValue:toValue forKeyPath:propertyFormatted]; [UIView commitAnimations]; - + goto complete; } } } - + } - -complete: + + complete: [tweenOperations addObject:operation]; return operation; } #if NS_BLOCKS_AVAILABLE -- (PRTweenOperation*)addTweenPeriod:(PRTweenPeriod *)period - updateBlock:(void (^)(PRTweenPeriod *period))updateBlock - completionBlock:(void (^)())completeBlock { + +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(void (^)(PRTweenPeriod *period))updateBlock + completionBlock:(void (^)(BOOL finished))completeBlock { return [self addTweenPeriod:period updateBlock:updateBlock completionBlock:completeBlock timingFunction:self.defaultTimingFunction]; } -- (PRTweenOperation*)addTweenPeriod:(PRTweenPeriod *)period - updateBlock:(void (^)(PRTweenPeriod *period))anUpdateBlock - completionBlock:(void (^)())completeBlock - timingFunction:(PRTweenTimingFunction)timingFunction { - +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + updateBlock:(void (^)(PRTweenPeriod *period))anUpdateBlock + completionBlock:(void (^)(BOOL finished))completeBlock + timingFunction:(PRTweenTimingFunction)timingFunction { + PRTweenOperation *tweenOperation = [PRTweenOperation new]; - tweenOperation.period = period; + tweenOperation.period = period; tweenOperation.timingFunction = timingFunction; - tweenOperation.updateBlock = anUpdateBlock; - tweenOperation.completeBlock = completeBlock; + tweenOperation.updateBlock = anUpdateBlock; + tweenOperation.completeBlock = completeBlock; + tweenOperation.wasPreempted = NO; return [self addTweenOperation:tweenOperation]; - + } + #endif -- (PRTweenOperation*)addTweenPeriod:(PRTweenPeriod *)period target:(NSObject *)target selector:(SEL)selector { +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period target:(NSObject *)target selector:(SEL)selector { return [self addTweenPeriod:period target:target selector:selector timingFunction:self.defaultTimingFunction]; } -- (PRTweenOperation*)addTweenPeriod:(PRTweenPeriod *)period target:(NSObject *)target selector:(SEL)selector timingFunction:(PRTweenTimingFunction)timingFunction { - +- (PRTweenOperation *)addTweenPeriod:(PRTweenPeriod *)period + target:(NSObject *)target + selector:(SEL)selector + timingFunction:(PRTweenTimingFunction)timingFunction { + PRTweenOperation *tweenOperation = [PRTweenOperation new]; - tweenOperation.period = period; - tweenOperation.target = target; + tweenOperation.period = period; + tweenOperation.target = target; tweenOperation.timingFunction = timingFunction; tweenOperation.updateSelector = selector; - + tweenOperation.wasPreempted = NO; + return [self addTweenOperation:tweenOperation]; - + } - (void)removeTweenOperation:(PRTweenOperation *)tweenOperation { if (tweenOperation != nil) { if ([tweenOperations containsObject:tweenOperation]) { + tweenOperation.wasPreempted = YES; [expiredTweenOperations addObject:tweenOperation]; } } } +- (void)removeAllTweenOperations { + for (PRTweenOperation *tweenOperation in tweenOperations) { + tweenOperation.wasPreempted = YES; + [expiredTweenOperations addObject:tweenOperation]; + } +} + + (SEL)setterFromProperty:(NSString *)property { - return NSSelectorFromString([NSString stringWithFormat:@"set%@:", [property stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[property substringToIndex:1] capitalizedString]]]); + return NSSelectorFromString([NSString stringWithFormat:@"set%@:", [property stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[property substringToIndex:1] + capitalizedString]]]); } -- (void)update { +- (void) update { timeOffset += kPRTweenFramerate; - + for (PRTweenOperation *tweenOperation in tweenOperations) { - + PRTweenPeriod *period = tweenOperation.period; - + // if operation is delayed, pass over it for now if (timeOffset <= period.startOffset + period.delay) { continue; } - + CGFloat (*timingFunction)(CGFloat, CGFloat, CGFloat, CGFloat) = tweenOperation.timingFunction; if (timingFunction == NULL) { timingFunction = self.defaultTimingFunction; } - + if (timingFunction != NULL && tweenOperation.canUseBuiltAnimation == NO) { if (timeOffset <= period.startOffset + period.delay + period.duration) { if ([period isKindOfClass:[PRTweenLerpPeriod class]]) { if ([period conformsToProtocol:@protocol(PRTweenLerpPeriod)]) { - PRTweenLerpPeriod *lerpPeriod = (PRTweenLerpPeriod *)period; + PRTweenLerpPeriod *lerpPeriod = (PRTweenLerpPeriod *) period; CGFloat progress = timingFunction(timeOffset - period.startOffset - period.delay, 0.0, 1.0, period.duration); [lerpPeriod setProgress:progress]; } else { @@ -665,21 +1113,21 @@ - (void)update { period.tweenedValue = period.endValue; [expiredTweenOperations addObject:tweenOperation]; } - + NSObject *target = tweenOperation.target; SEL selector = tweenOperation.updateSelector; - + if (period != nil) { if (target != nil && selector != NULL) { - [target performSelector:selector withObject:period afterDelay:0]; + [target performSelector:selector withObject:period afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; } - + // Check to see if blocks/GCD are supported if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_4_0) { // fire off update block if (tweenOperation.updateBlock != NULL) { tweenOperation.updateBlock(period); - } + } } } } else if (tweenOperation.canUseBuiltAnimation == YES) { @@ -688,28 +1136,29 @@ - (void)update { } } } - + // clean up expired tween operations for (__strong PRTweenOperation *tweenOperation in expiredTweenOperations) { + + if (tweenOperation.completeSelector) [tweenOperation.target performSelector:tweenOperation.completeSelector withObject:nil afterDelay:0 inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; - if (tweenOperation.completeSelector) [tweenOperation.target performSelector:tweenOperation.completeSelector withObject:nil afterDelay:0]; // Check to see if blocks/GCD are supported - if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_4_0) { + if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_4_0) { if (tweenOperation.completeBlock != NULL) { - tweenOperation.completeBlock(); + tweenOperation.completeBlock(!tweenOperation.wasPreempted); } } - // @HACK: Come up with a better pattern for removing observers. - @try { + if (tweenOperation.observers == PRTweenHasTweenedValueObserver) { [tweenOperation removeObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedValue"]; - } @catch (id exception) { + tweenOperation.observers = tweenOperation.observers & ~PRTweenHasTweenedValueObserver; } - @try { + + if (tweenOperation.observers == PRTweenHasTweenedLerpObserver) { [tweenOperation removeObserver:[PRTween sharedInstance] forKeyPath:@"period.tweenedLerp"]; - } @catch (id exception) { + tweenOperation.observers = tweenOperation.observers & ~PRTweenHasTweenedLerpObserver; } - + [tweenOperations removeObject:tweenOperation]; tweenOperation = nil; } @@ -717,7 +1166,7 @@ - (void)update { } - (void)dealloc { - tweenOperations = nil; + tweenOperations = nil; expiredTweenOperations = nil; [timer invalidate]; diff --git a/lib/PRTweenLinearDamping.h b/lib/PRTweenLinearDamping.h new file mode 100644 index 0000000..fd2eb0a --- /dev/null +++ b/lib/PRTweenLinearDamping.h @@ -0,0 +1,7 @@ +// Created by Chris Harding on 06/05/2014. +// Copyright (c) 2014 Chris Harding. All rights reserved. +// + +#import + +CGFloat PRTweenTimingFunctionLinearDamping (CGFloat, CGFloat, CGFloat, CGFloat); diff --git a/lib/PRTweenLinearDamping.m b/lib/PRTweenLinearDamping.m new file mode 100644 index 0000000..186aa32 --- /dev/null +++ b/lib/PRTweenLinearDamping.m @@ -0,0 +1,110 @@ +// Created by Chris Harding on 06/05/2014. +// Copyright (c) 2014 Chris Harding. All rights reserved. +// + +#import "PRTweenLinearDamping.h" + +#define DAMPING_RATIO 0.6 +#define NATURAL_FREQUENCY 15.0 + +CGFloat PRTweenTimingFunctionLinearDamping (CGFloat t, CGFloat b, CGFloat c, CGFloat d) +{ + /* + Solution obtained from http://mathworld.wolfram.com/DampedSimpleHarmonicMotionOverdamping.html + + x(t) = Ae^{\gamma_+ t} + Be^{\gamma_- t} + + where ''A'' and ''B'' are determined by the initial conditions of the system: + + A = x(0)+\frac{\gamma_+x(0)-\dot{x}(0)}{\gamma_--\gamma_+} + B = -\frac{\gamma_+x(0)-\dot{x}(0)}{\gamma_--\gamma_+} + + For our system, the inital conditions are: + + x(0) = -c + + After calculating x(t), the return value required is: + + b + c + x(t) + + Note that duration is ignored - the system is instead determined by its damping ratio and natural frequency. + + */ + + // Input vars (these should be variable) + CGFloat dampingRatio = DAMPING_RATIO; + CGFloat naturalFrequency = NATURAL_FREQUENCY; + + // Shorthand + CGFloat w0 = naturalFrequency; + CGFloat L = dampingRatio; + + // Constants + const CGFloat epsilon = 0.0001; + + // Return value + CGFloat x; + + /* + If dampingRatio >1.0 then the system is over-damped. We do not currently handle this case since its value in an animation is limited. + */ + if (dampingRatio > 1.0 + epsilon) x = 0; + + + /* + If dampingRatio == 1.0 then the system is critically damped. A critically damped system converges to zero as fast as possible without oscillating. + + Solution for x(t) : + + x(t) = (A+Bt)\,e^{-\omega_0 t} + + A = x(0) + B = \dot{x}(0)+\omega_0x(0) + + */ + else if (dampingRatio > 1.0 - epsilon) { + + CGFloat w0t = w0 * t; + x = -c * (1 + w0t) * exp(-w0t); + } + + + /* + If dampingRatio < 1.0 then the system is under-damped. In this situation, the system will oscillate at the natural damped frequency: + + \omega_\mathrm{d} = \omega_0 \sqrt{1 - \zeta^2 } + + Solution for x(t) : + + x(t) = e^{- \zeta \omega_0 t} (A \cos\,(\omega_\mathrm{d}\,t) + B \sin\,(\omega_\mathrm{d}\,t )) + + A = x(0) + B = \frac{1}{\omega_\mathrm{d}}(\zeta\omega_0x(0)+\dot{x}(0)) + + */ + else { + + + CGFloat dampedFrequency = w0 * sqrt(1.0 - L*L); + CGFloat wd = dampedFrequency; + CGFloat wdt = wd * t; + + CGFloat A = -c; + CGFloat B = (L * w0 * -c) / wd; + + x = exp(-L * w0 * t) * (A*cos(wdt) + B*sin(wdt)); + + } + + /* + To ensure the function ends correctly, we snap it to the final value once it reches a certain threshold. + */ + if (fabs(x) < epsilon) x = 0.0; + + /* + After calculating x(t), the return value required is: b + c + x(t) + */ + return b + c + x; +}; + + diff --git a/lib/PRTweenTimingFunctions.m b/lib/PRTweenTimingFunctions.m index da42860..5161d8a 100755 --- a/lib/PRTweenTimingFunctions.m +++ b/lib/PRTweenTimingFunctions.m @@ -29,29 +29,39 @@ CGFloat PRTweenTimingFunctionLinear (CGFloat time, CGFloat begin, CGFloat change CGFloat PRTweenTimingFunctionBackOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { CGFloat s = 1.70158; - return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b; + t=t/d-1; + return c*(t*t*((s+1)*t + s) + 1) + b; } CGFloat PRTweenTimingFunctionBackIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { CGFloat s = 1.70158; - return c*(t/=d)*t*((s+1)*t - s) + b; + t/=d; + return c*t*t*((s+1)*t - s) + b; } CGFloat PRTweenTimingFunctionBackInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - CGFloat s = 1.70158; - if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b; - return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b; + CGFloat s = 1.70158; + if ((t/=d/2) < 1) { + s*=(1.525); + return c/2*(t*t*((s+1)*t - s)) + b; + } + t-=2; + s*=(1.525); + return c/2*(t*t*((s+1)*t + s) + 2) + b; } CGFloat PRTweenTimingFunctionBounceOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { if ((t/=d) < (1/2.75)) { return c*(7.5625*t*t) + b; } else if (t < (2/2.75)) { - return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; + t-=(1.5/2.75); + return c*(7.5625*t*t + .75) + b; } else if (t < (2.5/2.75)) { - return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; + t-=(2.25/2.75); + return c*(7.5625*t*t + .9375) + b; } else { - return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; + t-=(2.625/2.75); + return c*(7.5625*t*t + .984375) + b; } } @@ -65,34 +75,40 @@ CGFloat PRTweenTimingFunctionBounceInOut (CGFloat t, CGFloat b, CGFloat c, CGFlo } CGFloat PRTweenTimingFunctionCircOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return c * sqrt(1 - (t=t/d-1)*t) + b; + t=t/d-1; + return c * sqrt(1 - t*t) + b; } CGFloat PRTweenTimingFunctionCircIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return -c * (sqrt(1 - (t/=d)*t) - 1) + b; + t/=d; + return -c * (sqrt(1 - t*t) - 1) + b; } CGFloat PRTweenTimingFunctionCircInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { if ((t/=d/2) < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b; - return c/2 * (sqrt(1 - (t-=2)*t) + 1) + b; + t-=2; + return c/2 * (sqrt(1 - t*t) + 1) + b; } CGFloat PRTweenTimingFunctionCubicOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return c*((t=t/d-1)*t*t + 1) + b; + t=t/d-1; + return c*(t*t*t + 1) + b; } CGFloat PRTweenTimingFunctionCubicIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return c*(t/=d)*t*t + b; + t/=d; + return c*t*t*t + b; } CGFloat PRTweenTimingFunctionCubicInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { if ((t/=d/2) < 1) return c/2*t*t*t + b; - return c/2*((t-=2)*t*t + 2) + b; + t-=2; + return c/2*(t*t*t + 2) + b; } CGFloat PRTweenTimingFunctionElasticOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { CGFloat p = d*.3; - CGFloat s, a; + CGFloat s, a = .0; if (t==0) return b; if ((t/=d)==1) return b+c; if (!a || a < ABS(c)) { a=c; s=p/4; } else s = p/(2*M_PI) * asin (c/a); @@ -101,21 +117,26 @@ CGFloat PRTweenTimingFunctionElasticOut (CGFloat t, CGFloat b, CGFloat c, CGFloa CGFloat PRTweenTimingFunctionElasticIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { CGFloat p = d*.3; - CGFloat s, a; + CGFloat s, a = .0; if (t==0) return b; if ((t/=d)==1) return b+c; if (!a || a < ABS(c)) { a=c; s=p/4; } else s = p/(2*M_PI) * asin (c/a); - return -(a*pow(2,10*(t-=1)) * sin( (t*d-s)*(2*M_PI)/p )) + b; + t-=1; + return -(a*pow(2,10*t) * sin( (t*d-s)*(2*M_PI)/p )) + b; } CGFloat PRTweenTimingFunctionElasticInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { CGFloat p = d*(.3*1.5); - CGFloat s, a; + CGFloat s, a = .0; if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!a || a < ABS(c)) { a=c; s=p/4; } else s = p/(2*M_PI) * asin (c/a); - if (t < 1) return -.5*(a*pow(2,10*(t-=1)) * sin( (t*d-s)*(2*M_PI)/p )) + b; - return a*pow(2,-10*(t-=1)) * sin( (t*d-s)*(2*M_PI)/p )*.5 + c + b; + if (t < 1) { + t-=1; + return -.5*(a*pow(2,10*t) * sin( (t*d-s)*(2*M_PI)/p )) + b; + } + t-=1; + return a*pow(2,-10*t) * sin( (t*d-s)*(2*M_PI)/p )*.5 + c + b; } CGFloat PRTweenTimingFunctionExpoOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { @@ -134,42 +155,51 @@ CGFloat PRTweenTimingFunctionExpoInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat } CGFloat PRTweenTimingFunctionQuadOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return -c *(t/=d)*(t-2) + b; + t/=d; + return -c *t*(t-2) + b; } CGFloat PRTweenTimingFunctionQuadIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return c*(t/=d)*t + b; + t/=d; + return c*t*t + b; } CGFloat PRTweenTimingFunctionQuadInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { if ((t/=d/2) < 1) return c/2*t*t + b; - return -c/2 * ((--t)*(t-2) - 1) + b; + t--; + return -c/2 * (t*(t-2) - 1) + b; } CGFloat PRTweenTimingFunctionQuartOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return -c * ((t=t/d-1)*t*t*t - 1) + b; + t=t/d-1; + return -c * (t*t*t*t - 1) + b; } CGFloat PRTweenTimingFunctionQuartIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return c*(t/=d)*t*t*t + b; + t/=d; + return c*t*t*t*t + b; } CGFloat PRTweenTimingFunctionQuartInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { if ((t/=d/2) < 1) return c/2*t*t*t*t + b; - return -c/2 * ((t-=2)*t*t*t - 2) + b; + t-=2; + return -c/2 * (t*t*t*t - 2) + b; } CGFloat PRTweenTimingFunctionQuintOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return c*(t/=d)*t*t*t*t + b; + t=t/d-1; + return c*(t*t*t*t*t + 1) + b; } CGFloat PRTweenTimingFunctionQuintIn (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { - return c*((t=t/d-1)*t*t*t*t + 1) + b; + t/=d; + return c*t*t*t*t*t + b; } CGFloat PRTweenTimingFunctionQuintInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b; - return c/2*((t-=2)*t*t*t*t + 2) + b; + t-=2; + return c/2*(t*t*t*t*t + 2) + b; } CGFloat PRTweenTimingFunctionSineOut (CGFloat t, CGFloat b, CGFloat c, CGFloat d) { @@ -197,4 +227,4 @@ CGFloat PRTweenTimingFunctionSineInOut (CGFloat t, CGFloat b, CGFloat c, CGFloat CGFloat (*PRTweenTimingFunctionCACustom(CAMediaTimingFunction *timingFunction))(CGFloat, CGFloat, CGFloat, CGFloat) { return &PRTweenTimingFunctionLinear; -} \ No newline at end of file +}