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