POPAnimationExtras.mm 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /**
  2. Copyright (c) 2014-present, Facebook, Inc.
  3. All rights reserved.
  4. This source code is licensed under the BSD-style license found in the
  5. LICENSE file in the root directory of this source tree. An additional grant
  6. of patent rights can be found in the PATENTS file in the same directory.
  7. */
  8. #import "POPAnimationExtras.h"
  9. #import "POPAnimationPrivate.h"
  10. #if TARGET_OS_IPHONE
  11. #import <UIKit/UIKit.h>
  12. #endif
  13. #if TARGET_IPHONE_SIMULATOR
  14. UIKIT_EXTERN float UIAnimationDragCoefficient(); // UIKit private drag coeffient, use judiciously
  15. #endif
  16. #import "POPMath.h"
  17. CGFloat POPAnimationDragCoefficient()
  18. {
  19. #if TARGET_IPHONE_SIMULATOR
  20. return UIAnimationDragCoefficient();
  21. #else
  22. return 1.0;
  23. #endif
  24. }
  25. @implementation CAAnimation (POPAnimationExtras)
  26. - (void)pop_applyDragCoefficient
  27. {
  28. CGFloat k = POPAnimationDragCoefficient();
  29. if (k != 0 && k != 1)
  30. self.speed = 1 / k;
  31. }
  32. @end
  33. @implementation POPSpringAnimation (POPAnimationExtras)
  34. static const CGFloat POPBouncy3NormalizationRange = 20.0;
  35. static const CGFloat POPBouncy3NormalizationScale = 1.7;
  36. static const CGFloat POPBouncy3BouncinessNormalizedMin = 0.0;
  37. static const CGFloat POPBouncy3BouncinessNormalizedMax = 0.8;
  38. static const CGFloat POPBouncy3SpeedNormalizedMin = 0.5;
  39. static const CGFloat POPBouncy3SpeedNormalizedMax = 200;
  40. static const CGFloat POPBouncy3FrictionInterpolationMax = 0.01;
  41. + (void)convertBounciness:(CGFloat)bounciness speed:(CGFloat)speed toTension:(CGFloat *)outTension friction:(CGFloat *)outFriction mass:(CGFloat *)outMass
  42. {
  43. double b = POPNormalize(bounciness / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange);
  44. b = POPProjectNormal(b, POPBouncy3BouncinessNormalizedMin, POPBouncy3BouncinessNormalizedMax);
  45. double s = POPNormalize(speed / POPBouncy3NormalizationScale, 0, POPBouncy3NormalizationRange);
  46. CGFloat tension = POPProjectNormal(s, POPBouncy3SpeedNormalizedMin, POPBouncy3SpeedNormalizedMax);
  47. CGFloat friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax);
  48. tension = POP_ANIMATION_TENSION_FOR_QC_TENSION(tension);
  49. friction = POP_ANIMATION_FRICTION_FOR_QC_FRICTION(friction);
  50. if (outTension) {
  51. *outTension = tension;
  52. }
  53. if (outFriction) {
  54. *outFriction = friction;
  55. }
  56. if (outMass) {
  57. *outMass = 1.0;
  58. }
  59. }
  60. + (void)convertTension:(CGFloat)tension friction:(CGFloat)friction toBounciness:(CGFloat *)outBounciness speed:(CGFloat *)outSpeed
  61. {
  62. // Convert to QC values, in which our calculations are done.
  63. CGFloat qcFriction = QC_FRICTION_FOR_POP_ANIMATION_FRICTION(friction);
  64. CGFloat qcTension = QC_TENSION_FOR_POP_ANIMATION_TENSION(tension);
  65. // Friction is a function of bounciness and tension, according to the following:
  66. // friction = POPQuadraticOutInterpolation(b, POPBouncy3NoBounce(tension), POPBouncy3FrictionInterpolationMax);
  67. // Solve for bounciness, given a tension and friction.
  68. CGFloat nobounceTension = POPBouncy3NoBounce(qcTension);
  69. CGFloat bounciness1, bounciness2;
  70. POPQuadraticSolve((nobounceTension - POPBouncy3FrictionInterpolationMax), // a
  71. 2 * (POPBouncy3FrictionInterpolationMax - nobounceTension), // b
  72. (nobounceTension - qcFriction), // c
  73. bounciness1, // x1
  74. bounciness2); // x2
  75. // Choose the quadratic solution within the normalized bounciness range
  76. CGFloat projectedNormalizedBounciness = (bounciness2 < POPBouncy3BouncinessNormalizedMax) ? bounciness2 : bounciness1;
  77. CGFloat projectedNormalizedSpeed = qcTension;
  78. // Reverse projection + normalization
  79. CGFloat bounciness = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3BouncinessNormalizedMax - POPBouncy3BouncinessNormalizedMin)) * (projectedNormalizedBounciness - POPBouncy3BouncinessNormalizedMin);
  80. CGFloat speed = ((POPBouncy3NormalizationRange * POPBouncy3NormalizationScale) / (POPBouncy3SpeedNormalizedMax - POPBouncy3SpeedNormalizedMin)) * (projectedNormalizedSpeed - POPBouncy3SpeedNormalizedMin);
  81. // Write back results
  82. if (outBounciness) {
  83. *outBounciness = bounciness;
  84. }
  85. if (outSpeed) {
  86. *outSpeed = speed;
  87. }
  88. }
  89. @end