| 
20 | 20 | 
 
  | 
21 | 21 | #import <UIKit/UIKit.h>  | 
22 | 22 | 
 
  | 
 | 23 | +#pragma mark - Private  | 
 | 24 | + | 
 | 25 | +static BOOL IsNumberValue(id someValue) {  | 
 | 26 | +  return [someValue isKindOfClass:[NSNumber class]];  | 
 | 27 | +}  | 
 | 28 | + | 
 | 29 | +static BOOL IsCGPointType(id someValue) {  | 
 | 30 | +  if ([someValue isKindOfClass:[NSValue class]]) {  | 
 | 31 | +    NSValue *asValue = (NSValue *)someValue;  | 
 | 32 | +    const char *objCType = @encode(CGPoint);  | 
 | 33 | +    return strncmp(asValue.objCType, objCType, strlen(objCType)) == 0;  | 
 | 34 | +  }  | 
 | 35 | +  return NO;  | 
 | 36 | +}  | 
 | 37 | + | 
 | 38 | +static BOOL IsCGSizeType(id someValue) {  | 
 | 39 | +  if ([someValue isKindOfClass:[NSValue class]]) {  | 
 | 40 | +    NSValue *asValue = (NSValue *)someValue;  | 
 | 41 | +    const char *objCType = @encode(CGSize);  | 
 | 42 | +    return strncmp(asValue.objCType, objCType, strlen(objCType)) == 0;  | 
 | 43 | +  }  | 
 | 44 | +  return NO;  | 
 | 45 | +}  | 
 | 46 | + | 
 | 47 | +#pragma mark - Public  | 
 | 48 | + | 
23 | 49 | CABasicAnimation *MDMAnimationFromTiming(MDMMotionTiming timing, CGFloat timeScaleFactor) {  | 
24 | 50 |   CABasicAnimation *animation;  | 
25 | 51 |   switch (timing.curve.type) {  | 
@@ -67,17 +93,7 @@ void MDMConfigureAnimation(CABasicAnimation *animation,  | 
67 | 93 |     return; // Nothing to do here.  | 
68 | 94 |   }  | 
69 | 95 | 
 
  | 
70 |  | -  // We can't infer the from/to value types from the animation if the values are NSValue types, so  | 
71 |  | -  // we map known key paths to their data types here:  | 
72 |  | -  static NSSet *sizeKeyPaths = nil;  | 
73 |  | -  static NSSet *positionKeyPaths = nil;  | 
74 |  | -  static dispatch_once_t onceToken;  | 
75 |  | -  dispatch_once(&onceToken, ^{  | 
76 |  | -    sizeKeyPaths = [NSSet setWithArray:@[@"bounds.size", @"shadowOffset"]];  | 
77 |  | -    positionKeyPaths = [NSSet setWithArray:@[@"position", @"anchorPoint"]];  | 
78 |  | -  });  | 
79 |  | - | 
80 |  | -  if ([animation.toValue isKindOfClass:[NSNumber class]]) {  | 
 | 96 | +  if (IsNumberValue(animation.toValue)) {  | 
81 | 97 |     // Non-additive animations animate along a direct path between fromValue and toValue, regardless  | 
82 | 98 |     // of the model layer. Additive animations, on the other hand, animate towards the layer's model  | 
83 | 99 |     // value by applying this formula:  | 
@@ -166,7 +182,7 @@ void MDMConfigureAnimation(CABasicAnimation *animation,  | 
166 | 182 |       springAnimation.initialVelocity = absoluteInitialVelocity / displacement;  | 
167 | 183 |     }  | 
168 | 184 | 
 
  | 
169 |  | -  } else if ([sizeKeyPaths containsObject:animation.keyPath]) {  | 
 | 185 | +  } else if (IsCGSizeType(animation.toValue)) {  | 
170 | 186 |     CGSize from = [animation.fromValue CGSizeValue];  | 
171 | 187 |     CGSize to = [animation.toValue CGSizeValue];  | 
172 | 188 |     CGSize additiveDisplacement = CGSizeMake(from.width - to.width, from.height - to.height);  | 
@@ -198,7 +214,7 @@ void MDMConfigureAnimation(CABasicAnimation *animation,  | 
198 | 214 |       springAnimation.initialVelocity = absoluteInitialVelocity / displacement;  | 
199 | 215 |     }  | 
200 | 216 | 
 
  | 
201 |  | -  } else if ([positionKeyPaths containsObject:animation.keyPath]) {  | 
 | 217 | +  } else if (IsCGPointType(animation.toValue)) {  | 
202 | 218 |     CGPoint from = [animation.fromValue CGPointValue];  | 
203 | 219 |     CGPoint to = [animation.toValue CGPointValue];  | 
204 | 220 |     CGPoint additiveDisplacement = CGPointMake(from.x - to.x, from.y - to.y);  | 
 | 
0 commit comments