Advertisement
Guest User

Untitled

a guest
Jul 17th, 2017
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 4.54 KB | None | 0 0
  1. open class HeartLayer: CALayer {
  2.    
  3.     fileprivate struct Durations {
  4.         static let Full: TimeInterval = 3
  5.         static let Bloom: TimeInterval = 0.5
  6.     }
  7.    
  8.     public init(frame: CGRect) {
  9.         super.init()
  10.         position = frame.origin
  11.         bounds = frame
  12.         backgroundColor = UIColor.clear.cgColor
  13.         anchorPoint = CGPoint(x: 0.5, y: 1)
  14.         contents = #imageLiteral(resourceName: "heart").cgImage
  15.     }
  16.    
  17.     required public init?(coder aDecoder: NSCoder) {
  18.         super.init(coder: aDecoder)
  19.     }
  20.    
  21.     // MARK: Animations
  22.    
  23.     open func animateInView(_ view: UIView) {
  24.        
  25.         prepareForAnimation()
  26.         performBloomAnimation()
  27.         addPathAnimation(inView: view)
  28.     }
  29.    
  30.     fileprivate func prepareForAnimation() {
  31. //        transform = CGAffineTransform(scaleX: 0, y: 0)
  32. //        transform = CATransform3D(
  33. //        alpha = 0
  34.     }
  35.    
  36.     fileprivate func performBloomAnimation() {
  37.        
  38.         spring(Durations.Bloom, delay: 0.0, damping: 0.6, velocity: 0.8) {
  39.             //f.alpha = 0.9
  40.         }
  41.     }
  42.    
  43.     fileprivate func slightRotationAnimation(withDuration duration: TimeInterval = Durations.Full, _ direction: RotationDirection) {
  44.         let rotationFraction = randomNumber(10)
  45.         let rotate = CABasicAnimation(keyPath: "transform.rotation")
  46.         rotate.fromValue = 0
  47.         rotate.toValue =  direction.rawValue * PI / (16 + rotationFraction * 0.2)
  48.         rotate.duration = Durations.Full
  49.         rotate.fillMode = kCAFillModeForwards;
  50.         rotate.isRemovedOnCompletion = false
  51.         add(rotate, forKey: "transform.rotation")
  52.     }
  53.    
  54.     fileprivate func travelPath(inView view: UIView) -> UIBezierPath? {
  55.         guard let endPointDirection = RotationDirection(rawValue: CGFloat(1 - Int(2 * randomNumber(2)))) else { return nil }
  56.        
  57.         let heartCenterX = position.x + bounds.width / 2
  58.         let heartSize = bounds.width
  59.         let viewHeight = view.bounds.height
  60.        
  61.         //random end point
  62.         let endPointX = heartCenterX + (endPointDirection.rawValue * randomNumber(2 * heartSize))
  63.         let endPointY = viewHeight - (viewHeight / 6.0 + randomNumber(viewHeight / 4.0))
  64.         let endPoint = CGPoint(x: endPointX, y: endPointY)
  65.        
  66.         //random Control Points
  67.         let travelDirection = CGFloat(1 - Int(2 * randomNumber(2)))
  68.         let xDelta = (heartSize / 2.0 + randomNumber(2 * heartSize)) * travelDirection
  69.         let yDelta = max(endPoint.y ,max(randomNumber(8 * heartSize), heartSize))
  70.         let controlPoint1 = CGPoint(x: heartCenterX + xDelta, y: viewHeight - yDelta)
  71.         let controlPoint2 = CGPoint(x: heartCenterX - 2 * xDelta, y: yDelta)
  72.        
  73.         let path = UIBezierPath()
  74.         let center = CGPoint(x: position.x + bounds.width / 2, y: position.y + bounds.height / 2)
  75.         path.move(to: center)
  76.         path.addCurve(to: endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
  77.         return path
  78.     }
  79.    
  80.     fileprivate func addPathAnimation(inView view: UIView) {
  81.         guard let heartTravelPath = travelPath(inView: view) else { return }
  82.         let keyFrameAnimation = CAKeyframeAnimation(keyPath: "position")
  83.         keyFrameAnimation.path = heartTravelPath.cgPath
  84.         keyFrameAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
  85.         let durationAdjustment = 4 * TimeInterval(heartTravelPath.bounds.height / view.bounds.height)
  86.         let duration = Durations.Full + durationAdjustment
  87.         keyFrameAnimation.duration = duration
  88.        
  89.         add(keyFrameAnimation, forKey: "positionOnPath")
  90.        
  91.         animateToFinalAlpha(withDuration: duration)
  92.        
  93.         guard let rotationDirection = RotationDirection(rawValue: CGFloat(1 - Int(2 * randomNumber(2)))) else { return }
  94.         slightRotationAnimation(withDuration: duration, rotationDirection)
  95.     }
  96.    
  97.     fileprivate func animateToFinalAlpha(withDuration duration: TimeInterval = Durations.Full) {
  98.         let animation = CABasicAnimation(keyPath: "opacity")
  99.         animation.fromValue = 1
  100.         animation.toValue = 0
  101.         animation.duration = duration
  102.         animation.delegate = self
  103.         animation.fillMode = kCAFillModeForwards;
  104.         animation.isRemovedOnCompletion = false
  105.         add(animation, forKey: "hide")
  106.        
  107.     }
  108. }
  109.  
  110. extension HeartLayer: CAAnimationDelegate {
  111.     public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
  112.         removeFromSuperlayer()
  113.     }
  114. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement