1 // Copyright (c) 2018, Applidium. All rights reserved 2 // SpringOverlayTranslationAnimationController.swift 3 // OverlayContainer 4 // 5 // Created by Gaétan Zanella on 21/11/2018. 6 // 7 8 import UIKit 9 10 private struct Constant { 11 static let defaultMass: CGFloat = 1 12 static let defaultDamping: CGFloat = 0.7 13 static let defaultRigidDamping: CGFloat = 0.9 14 static let defaultResponse: CGFloat = 0.3 15 static let minimumDamping: CGFloat = 1 16 static let minimumVelocityConsideration: CGFloat = 150 17 static let maximumVelocityConsideration: CGFloat = 3000 18 } 19 20 /// An `OverlayAnimatedTransitioning` implementation based on `UISpringTimingParameters`. 21 public class SpringOverlayTranslationAnimationController: OverlayAnimatedTransitioning { 22 23 public var mass: CGFloat = Constant.defaultMass 24 public var damping: CGFloat = Constant.defaultDamping 25 public var response: CGFloat = Constant.defaultResponse 26 27 // MARK: - Life Cycle 28 29 public init() {} 30 31 public init(style: OverlayContainerViewController.OverlayStyle) { 32 switch style { 33 case .expandableHeight, .rigid: 34 // (gz) 2019-06-15 We also nullify the damping value when using rigid styles 35 // to avoid the panel to be lifted above the bottom of the screen. 36 damping = Constant.defaultRigidDamping 37 case .flexibleHeight: 38 damping = Constant.defaultDamping 39 } 40 } 41 42 // MARK: - OverlayAnimatedTransitioning 43 interruptibleAnimatornull44 public func interruptibleAnimator(using context: OverlayContainerContextTransitioning) -> UIViewImplicitlyAnimating { 45 let velocity = min( 46 Constant.maximumVelocityConsideration, 47 max(abs(context.velocity.y), Constant.minimumVelocityConsideration) 48 ) 49 let velocityRange = Constant.maximumVelocityConsideration - Constant.minimumVelocityConsideration 50 let normalizedVelocity = (velocity - Constant.minimumVelocityConsideration) / velocityRange 51 let normalizedDamping = normalizedVelocity * (damping - Constant.minimumDamping) + Constant.minimumDamping 52 let timing = UISpringTimingParameters( 53 damping: normalizedDamping, 54 response: response, 55 mass: mass 56 ) 57 return UIViewPropertyAnimator( 58 duration: 0, // duration is ignored when using `UISpringTimingParameters.init(mass:stiffness:damping:initialVelocity)` 59 timingParameters: timing 60 ) 61 } 62 } 63 64 extension UISpringTimingParameters { 65 convenience init(damping: CGFloat, response: CGFloat, mass: CGFloat) { 66 let stiffness = pow(2 * .pi / response, 2) 67 let damp = 4 * .pi * damping / response 68 self.init(mass: mass, stiffness: stiffness, damping: damp, initialVelocity: .zero) 69 } 70 } 71