Advertisement
Guest User

Untitled

a guest
Jul 16th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 6.24 KB | None | 0 0
  1. import UIKit
  2.  
  3. class Elastic: UIView {
  4.  
  5.    
  6.     //наши опорный точки для шэйпа чтобы по пути шэйп нарисовать
  7.     private let topControlPointView = UIView()
  8.     private let bottomControlPointView = UIView()
  9.     private let leftControlPointView = UIView()
  10.     private let rightControlPointView = UIView()
  11.    
  12.    
  13.     //шэйп который будет трансформироваться
  14.     private let elasticShape: CAShapeLayer = CAShapeLayer()
  15.    
  16.     //на сколько будет желейная
  17.     public var contactForce: CGFloat = 20
  18.    
  19.     //с конструкторами и так все понятно
  20.     override init(frame: CGRect) {
  21.         super.init(frame: frame)
  22.         setupCompanents()
  23.     }
  24.    
  25.     required init?(coder aDecoder: NSCoder) {
  26.         super.init(coder: aDecoder)!
  27.         setupCompanents()
  28.     }
  29.    
  30.     private func setupCompanents() {
  31.        
  32.         //настраиваем цвет шейпа
  33.         elasticShape.fillColor = self.backgroundColor?.cgColor
  34.         elasticShape.path = UIBezierPath(rect: self.bounds).cgPath
  35.         layer.addSublayer(elasticShape)
  36.        
  37.        
  38.         //создаем опорные точки, размеры вообще тут для видимости типо чтобы синенькие были
  39.         for controlPoint in [topControlPointView, bottomControlPointView, leftControlPointView, rightControlPointView] {
  40.             addSubview(controlPoint)
  41.             controlPoint.frame = CGRect(x: 0, y: 0, width: 5, height: 5)
  42. //            controlPoint.backgroundColor = .blue
  43.         }
  44.        
  45.         positionControlPoint()
  46.        
  47.         //чтобы шэйп норм выходил за грани и вьюха со своим цветом не мешало
  48.         backgroundColor = .clear
  49.         clipsToBounds = false
  50.        
  51.     }
  52.    
  53.     //соответственно те самые опорные поинты которые будут нужны для пути который нужен для шэйпа
  54.     private func positionControlPoint() {
  55.        
  56.         topControlPointView.center = CGPoint(x: bounds.midX, y: 0)
  57.         rightControlPointView.center = CGPoint(x: bounds.maxX, y: bounds.midY)
  58.         bottomControlPointView.center = CGPoint(x: bounds.midX, y: bounds.maxY)
  59.         leftControlPointView.center = CGPoint(x: 0, y: bounds.midY)
  60.        
  61.     }
  62.    
  63.     //создание пути
  64.     private func bezierPathForControlPoints() -> CGPath {
  65.        
  66.         let path = UIBezierPath()
  67.        
  68.         let top = topControlPointView.layer.presentation()?.position
  69.         let right = rightControlPointView.layer.presentation()?.position
  70.         let bottom = bottomControlPointView.layer.presentation()?.position
  71.         let left = leftControlPointView.layer.presentation()?.position
  72.        
  73.         let width = self.frame.size.width
  74.         let height = self.frame.size.height
  75.        
  76.         path.move(to: CGPoint(x: 0, y: 0))
  77.         path.addQuadCurve(to: CGPoint(x: width, y: 0), controlPoint: top!)
  78.         path.addQuadCurve(to: CGPoint(x: width, y: height), controlPoint: right!)
  79.         path.addQuadCurve(to: CGPoint(x: 0, y: height), controlPoint: bottom!)
  80.         path.addQuadCurve(to: CGPoint(x: 0, y: 0), controlPoint: left!)
  81.        
  82.         return path.cgPath
  83.        
  84.     }
  85.    
  86.     //штука чтобы перерисовать путь можно было
  87.     private lazy var displayLink: CADisplayLink = {
  88.         let displayLink = CADisplayLink(target: self, selector: #selector(self.updateLoop))
  89.         displayLink.add(to: .current, forMode: RunLoopMode.commonModes)
  90.         return displayLink
  91.     }()
  92.    
  93.     //эту штука апдэйтит путь, чтобы красиво было
  94.     @objc private func updateLoop() {
  95.         elasticShape.path = bezierPathForControlPoints()
  96.     }
  97.    
  98.     //запускает апдэйт
  99.     private func startUpdateLoop() {
  100.         displayLink.isPaused = false
  101.     }
  102.    
  103.     //останавливает апдэйт
  104.     private func stopDisplayLoop() {
  105.         displayLink.isPaused = true
  106.     }
  107.    
  108.     //сама анимашка вместе с новыми параметрами
  109.     //usingSpringWithDamping насколько сильно будет шататься
  110.     //initialSpringVelocity насколько долго
  111.     //вроде как
  112.     private func animateControlPoints() {
  113.        
  114.         UIView.animate(withDuration: 0.25,
  115.                        delay: 0,
  116.                        usingSpringWithDamping: 0.9,
  117.                        initialSpringVelocity: 1.5,
  118.                        options: [],
  119.                        animations: {
  120.            
  121.             self.topControlPointView.center.y -= self.contactForce
  122.             self.rightControlPointView.center.x += self.contactForce
  123.             self.bottomControlPointView.center.y += self.contactForce
  124.             self.leftControlPointView.center.x -= self.contactForce
  125.            
  126.         }, completion: {_ in
  127.            
  128.         })
  129.        
  130.     }
  131.    
  132.     //начало анимации
  133.     override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
  134.         startUpdateLoop()
  135.         animateControlPoints()
  136.     }
  137.    
  138.     //конец анимации
  139.     override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
  140.        
  141.         UIView.animate(withDuration: 0.45,
  142.                        delay: 0,
  143.                        usingSpringWithDamping: 0.15,
  144.                        initialSpringVelocity: 5.5,
  145.                        options: [],
  146.                        animations: {
  147.                        
  148.                         self.positionControlPoint()
  149.                        
  150.         },
  151.                        completion: {_ in
  152.                         self.stopDisplayLoop()
  153.         })
  154.  
  155.     }
  156.    
  157.     //чтобы вьха не мешала а заливкой служил сам шэйп
  158.     override var backgroundColor: UIColor? {
  159.         willSet{
  160.             if let newValue = newValue {
  161.                 elasticShape.fillColor = newValue.cgColor
  162.                 super.backgroundColor = UIColor.clear
  163.             }
  164.         }
  165.     }
  166.  
  167. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement