Created
August 4, 2013 05:36
-
-
Save Shilo/6149310 to your computer and use it in GitHub Desktop.
A category for Sparrow that allows setting the repeat total time and repeat start values of properties.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SPTween+RepeatValues.h | |
// Sparrow 2.X | |
// | |
// Created by Shilo White on 8/3/13. | |
// | |
#import "SPTween.h" | |
@interface SPTween (RepeatValues) | |
@property (nonatomic, assign) double repeatTotalTime; | |
- (void)animateProperty:(NSString*)property targetValue:(float)endValue repeatStartValue:(float)repeatStartValue; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SPTween+RepeatValues.m | |
// Sparrow 2.X | |
// | |
// Created by Shilo White on 8/3/13. | |
// | |
#import "SPTween+RepeatValues.h" | |
#import "SPTransitions.h" | |
#import "SPTweenedProperty.h" | |
#import <objc/runtime.h> | |
#define TRANS_SUFFIX @":" | |
typedef float (*FnPtrTransition) (id, SEL, float); | |
@interface SPTweenedProperty (RepeatValues) | |
@property (nonatomic, assign) NSNumber *repeatStartValue; | |
@end | |
@interface SPTween () { | |
id _target; | |
SEL _transition; | |
IMP _transitionFunc; | |
NSMutableArray *_properties; | |
double _totalTime; | |
double _currentTime; | |
double _delay; | |
int _repeatCount; | |
double _repeatDelay; | |
BOOL _reverse; | |
int _currentCycle; | |
SPCallbackBlock _onStart; | |
SPCallbackBlock _onUpdate; | |
SPCallbackBlock _onRepeat; | |
SPCallbackBlock _onComplete; | |
} | |
@end | |
@implementation SPTween (RepeatValues) | |
#pragma clang diagnostic push | |
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" | |
- (id)initWithTarget:(id)target time:(double)time transition:(NSString*)transition | |
{ | |
if ((self = [super init])) | |
{ | |
_target = target; | |
self.repeatTotalTime = _totalTime = MAX(0.0001, time); // zero is not allowed | |
_currentTime = 0; | |
_delay = 0; | |
_properties = [[NSMutableArray alloc] init]; | |
_repeatCount = 1; | |
_currentCycle = -1; | |
_reverse = NO; | |
// create function pointer for transition | |
NSString *transMethod = [transition stringByAppendingString:TRANS_SUFFIX]; | |
_transition = NSSelectorFromString(transMethod); | |
if (![SPTransitions respondsToSelector:_transition]) | |
[NSException raise:SP_EXC_INVALID_OPERATION | |
format:@"transition not found: '%@'", transition]; | |
_transitionFunc = [SPTransitions methodForSelector:_transition]; | |
} | |
return self; | |
} | |
- (void)setRepeatTotalTime:(double)repeatTotalTime | |
{ | |
objc_setAssociatedObject(self, @"repeatTotalTime", [NSNumber numberWithDouble:repeatTotalTime], OBJC_ASSOCIATION_RETAIN); | |
} | |
- (double)repeatTotalTime | |
{ | |
return [objc_getAssociatedObject(self, @"repeatTotalTime") doubleValue]; | |
} | |
- (void)animateProperty:(NSString*)property targetValue:(float)endValue repeatStartValue:(float)repeatStartValue | |
{ | |
if (!_target) return; | |
SPTweenedProperty *tweenedProp = [[SPTweenedProperty alloc] initWithTarget:_target name:property endValue:endValue]; | |
tweenedProp.repeatStartValue = [NSNumber numberWithFloat:repeatStartValue]; | |
[_properties addObject:tweenedProp]; | |
} | |
- (void)advanceTime:(double)time | |
{ | |
if (time == 0.0 || (_repeatCount == 1 && _currentTime == _totalTime)) | |
return; // nothing to do | |
else if ((_repeatCount == 0 || _repeatCount > 1) && _currentTime == _totalTime) | |
_currentTime = 0.0; | |
double previousTime = _currentTime; | |
double restTime = _totalTime - _currentTime; | |
double carryOverTime = time > restTime ? time - restTime : 0.0; | |
_currentTime = MIN(_totalTime, _currentTime + time); | |
BOOL isStarting = _currentCycle < 0 && previousTime <= 0 && _currentTime > 0; | |
if (_currentTime <= 0) return; // the delay is not over yet | |
if (isStarting) | |
{ | |
_currentCycle++; | |
if (_onStart) _onStart(); | |
} | |
float ratio = _currentTime / _totalTime; | |
BOOL reversed = _reverse && (_currentCycle % 2 == 1); | |
FnPtrTransition transFunc = (FnPtrTransition) _transitionFunc; | |
Class transClass = [SPTransitions class]; | |
for (SPTweenedProperty *prop in _properties) | |
{ | |
if (isStarting) prop.startValue = prop.currentValue; | |
float transitionValue = reversed ? transFunc(transClass, _transition, 1.0 - ratio) : | |
transFunc(transClass, _transition, ratio); | |
prop.currentValue = prop.startValue + prop.delta * transitionValue; | |
} | |
if (_onUpdate) _onUpdate(); | |
if (previousTime < _totalTime && _currentTime >= _totalTime) | |
{ | |
if (_repeatCount == 0 || _repeatCount > 1) | |
{ | |
if (_currentCycle == 0) | |
{ | |
_totalTime = self.repeatTotalTime; | |
for (SPTweenedProperty *prop in _properties) | |
if (prop.repeatStartValue) | |
prop.startValue = [prop.repeatStartValue floatValue]; | |
} | |
_currentTime = -_repeatDelay; | |
_currentCycle++; | |
if (_repeatCount > 1) _repeatCount--; | |
if (_onRepeat) _onRepeat(); | |
} | |
else | |
{ | |
[self dispatchEventWithType:SP_EVENT_TYPE_REMOVE_FROM_JUGGLER]; | |
if (_onComplete) _onComplete(); | |
} | |
} | |
if (carryOverTime) | |
[self advanceTime:carryOverTime]; | |
} | |
#pragma clang diagnostic pop | |
@end | |
@implementation SPTweenedProperty (RepeatValues) | |
- (void)setRepeatStartValue:(NSNumber *)repeatStartValue | |
{ | |
objc_setAssociatedObject(self, @"repeatStartValue", repeatStartValue, OBJC_ASSOCIATION_RETAIN); | |
} | |
- (NSNumber *)repeatStartValue | |
{ | |
return objc_getAssociatedObject(self, @"repeatStartValue"); | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment