You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
5.8 KiB
203 lines
5.8 KiB
/** |
|
Copyright (c) 2014-present, Facebook, Inc. |
|
All rights reserved. |
|
|
|
This source code is licensed under the BSD-style license found in the |
|
LICENSE file in the root directory of this source tree. An additional grant |
|
of patent rights can be found in the PATENTS file in the same directory. |
|
*/ |
|
|
|
#import "POPDecayAnimationInternal.h" |
|
|
|
#if TARGET_OS_IPHONE |
|
#import <UIKit/UIKit.h> |
|
#endif |
|
|
|
const POPValueType supportedVelocityTypes[6] = { kPOPValuePoint, kPOPValueInteger, kPOPValueFloat, kPOPValueRect, kPOPValueSize, kPOPValueEdgeInsets }; |
|
|
|
@implementation POPDecayAnimation |
|
|
|
#pragma mark - Lifecycle |
|
|
|
#undef __state |
|
#define __state ((POPDecayAnimationState *)_state) |
|
|
|
+ (instancetype)animation |
|
{ |
|
return [[self alloc] init]; |
|
} |
|
|
|
+ (instancetype)animationWithPropertyNamed:(NSString *)aName |
|
{ |
|
POPDecayAnimation *anim = [self animation]; |
|
anim.property = [POPAnimatableProperty propertyWithName:aName]; |
|
return anim; |
|
} |
|
|
|
- (id)init |
|
{ |
|
return [self _init]; |
|
} |
|
|
|
- (void)_initState |
|
{ |
|
_state = new POPDecayAnimationState(self); |
|
} |
|
|
|
#pragma mark - Properties |
|
|
|
DEFINE_RW_PROPERTY(POPDecayAnimationState, deceleration, setDeceleration:, CGFloat, __state->toVec = NULL;); |
|
|
|
@dynamic velocity; |
|
|
|
- (id)toValue |
|
{ |
|
[self _ensureComputedProperties]; |
|
return POPBox(__state->toVec, __state->valueType); |
|
} |
|
|
|
- (CFTimeInterval)duration |
|
{ |
|
[self _ensureComputedProperties]; |
|
return __state->duration; |
|
} |
|
|
|
- (void)setFromValue:(id)fromValue |
|
{ |
|
super.fromValue = fromValue; |
|
[self _invalidateComputedProperties]; |
|
} |
|
|
|
- (void)setToValue:(id)aValue |
|
{ |
|
// no-op |
|
NSLog(@"ignoring to value on decay animation %@", self); |
|
} |
|
|
|
- (id)reversedVelocity |
|
{ |
|
id reversedVelocity = nil; |
|
|
|
POPValueType velocityType = POPSelectValueType(self.originalVelocity, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes)); |
|
if (velocityType == kPOPValueFloat) { |
|
#if CGFLOAT_IS_DOUBLE |
|
CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity doubleValue]; |
|
#else |
|
CGFloat originalVelocityFloat = [(NSNumber *)self.originalVelocity floatValue]; |
|
#endif |
|
NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityFloat); |
|
reversedVelocity = negativeOriginalVelocityNumber; |
|
} else if (velocityType == kPOPValueInteger) { |
|
NSInteger originalVelocityInteger = [(NSNumber *)self.originalVelocity integerValue]; |
|
NSNumber *negativeOriginalVelocityNumber = @(-originalVelocityInteger); |
|
reversedVelocity = negativeOriginalVelocityNumber; |
|
} else if (velocityType == kPOPValuePoint) { |
|
CGPoint originalVelocityPoint = [self.originalVelocity CGPointValue]; |
|
CGPoint negativeOriginalVelocityPoint = CGPointMake(-originalVelocityPoint.x, -originalVelocityPoint.y); |
|
reversedVelocity = [NSValue valueWithCGPoint:negativeOriginalVelocityPoint]; |
|
} else if (velocityType == kPOPValueRect) { |
|
CGRect originalVelocityRect = [self.originalVelocity CGRectValue]; |
|
CGRect negativeOriginalVelocityRect = CGRectMake(-originalVelocityRect.origin.x, -originalVelocityRect.origin.y, -originalVelocityRect.size.width, -originalVelocityRect.size.height); |
|
reversedVelocity = [NSValue valueWithCGRect:negativeOriginalVelocityRect]; |
|
} else if (velocityType == kPOPValueSize) { |
|
CGSize originalVelocitySize = [self.originalVelocity CGSizeValue]; |
|
CGSize negativeOriginalVelocitySize = CGSizeMake(-originalVelocitySize.width, -originalVelocitySize.height); |
|
reversedVelocity = [NSValue valueWithCGSize:negativeOriginalVelocitySize]; |
|
} else if (velocityType == kPOPValueEdgeInsets) { |
|
#if TARGET_OS_IPHONE |
|
UIEdgeInsets originalVelocityInsets = [self.originalVelocity UIEdgeInsetsValue]; |
|
UIEdgeInsets negativeOriginalVelocityInsets = UIEdgeInsetsMake(-originalVelocityInsets.top, -originalVelocityInsets.left, -originalVelocityInsets.bottom, -originalVelocityInsets.right); |
|
reversedVelocity = [NSValue valueWithUIEdgeInsets:negativeOriginalVelocityInsets]; |
|
#endif |
|
} |
|
|
|
return reversedVelocity; |
|
} |
|
|
|
- (id)originalVelocity |
|
{ |
|
return POPBox(__state->originalVelocityVec, __state->valueType); |
|
} |
|
|
|
- (id)velocity |
|
{ |
|
return POPBox(__state->velocityVec, __state->valueType); |
|
} |
|
|
|
- (void)setVelocity:(id)aValue |
|
{ |
|
POPValueType valueType = POPSelectValueType(aValue, supportedVelocityTypes, POP_ARRAY_COUNT(supportedVelocityTypes)); |
|
if (valueType != kPOPValueUnknown) { |
|
VectorRef vec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES); |
|
VectorRef origVec = POPUnbox(aValue, __state->valueType, __state->valueCount, YES); |
|
|
|
if (!vec_equal(vec, __state->velocityVec)) { |
|
__state->velocityVec = vec; |
|
__state->originalVelocityVec = origVec; |
|
|
|
if (__state->tracing) { |
|
[__state->tracer updateVelocity:aValue]; |
|
} |
|
|
|
[self _invalidateComputedProperties]; |
|
|
|
// automatically unpause active animations |
|
if (__state->active && __state->paused) { |
|
__state->fromVec = NULL; |
|
__state->setPaused(false); |
|
} |
|
} |
|
} else { |
|
__state->velocityVec = NULL; |
|
NSLog(@"Invalid velocity value for the decayAnimation: %@", aValue); |
|
} |
|
} |
|
|
|
#pragma mark - Utility |
|
|
|
- (void)_ensureComputedProperties |
|
{ |
|
if (NULL == __state->toVec) { |
|
__state->computeDuration(); |
|
__state->computeToValue(); |
|
} |
|
} |
|
|
|
- (void)_invalidateComputedProperties |
|
{ |
|
__state->toVec = NULL; |
|
__state->duration = 0; |
|
} |
|
|
|
- (void)_appendDescription:(NSMutableString *)s debug:(BOOL)debug |
|
{ |
|
[super _appendDescription:s debug:debug]; |
|
|
|
if (0 != self.duration) { |
|
[s appendFormat:@"; duration = %f", self.duration]; |
|
} |
|
|
|
if (__state->deceleration) { |
|
[s appendFormat:@"; deceleration = %f", __state->deceleration]; |
|
} |
|
} |
|
|
|
@end |
|
|
|
@implementation POPDecayAnimation (NSCopying) |
|
|
|
- (instancetype)copyWithZone:(NSZone *)zone { |
|
|
|
POPDecayAnimation *copy = [super copyWithZone:zone]; |
|
|
|
if (copy) { |
|
// Set the velocity to the animation's original velocity, not its current. |
|
copy.velocity = self.originalVelocity; |
|
copy.deceleration = self.deceleration; |
|
|
|
} |
|
|
|
return copy; |
|
} |
|
|
|
@end |