Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import UIKit
- class Elastic: UIView {
- //наши опорный точки для шэйпа чтобы по пути шэйп нарисовать
- private let topControlPointView = UIView()
- private let bottomControlPointView = UIView()
- private let leftControlPointView = UIView()
- private let rightControlPointView = UIView()
- //шэйп который будет трансформироваться
- private let elasticShape: CAShapeLayer = CAShapeLayer()
- //на сколько будет желейная
- public var contactForce: CGFloat = 20
- //с конструкторами и так все понятно
- override init(frame: CGRect) {
- super.init(frame: frame)
- setupCompanents()
- }
- required init?(coder aDecoder: NSCoder) {
- super.init(coder: aDecoder)!
- setupCompanents()
- }
- private func setupCompanents() {
- //настраиваем цвет шейпа
- elasticShape.fillColor = self.backgroundColor?.cgColor
- elasticShape.path = UIBezierPath(rect: self.bounds).cgPath
- layer.addSublayer(elasticShape)
- //создаем опорные точки, размеры вообще тут для видимости типо чтобы синенькие были
- for controlPoint in [topControlPointView, bottomControlPointView, leftControlPointView, rightControlPointView] {
- addSubview(controlPoint)
- controlPoint.frame = CGRect(x: 0, y: 0, width: 5, height: 5)
- // controlPoint.backgroundColor = .blue
- }
- positionControlPoint()
- //чтобы шэйп норм выходил за грани и вьюха со своим цветом не мешало
- backgroundColor = .clear
- clipsToBounds = false
- }
- //соответственно те самые опорные поинты которые будут нужны для пути который нужен для шэйпа
- private func positionControlPoint() {
- topControlPointView.center = CGPoint(x: bounds.midX, y: 0)
- rightControlPointView.center = CGPoint(x: bounds.maxX, y: bounds.midY)
- bottomControlPointView.center = CGPoint(x: bounds.midX, y: bounds.maxY)
- leftControlPointView.center = CGPoint(x: 0, y: bounds.midY)
- }
- //создание пути
- private func bezierPathForControlPoints() -> CGPath {
- let path = UIBezierPath()
- let top = topControlPointView.layer.presentation()?.position
- let right = rightControlPointView.layer.presentation()?.position
- let bottom = bottomControlPointView.layer.presentation()?.position
- let left = leftControlPointView.layer.presentation()?.position
- let width = self.frame.size.width
- let height = self.frame.size.height
- path.move(to: CGPoint(x: 0, y: 0))
- path.addQuadCurve(to: CGPoint(x: width, y: 0), controlPoint: top!)
- path.addQuadCurve(to: CGPoint(x: width, y: height), controlPoint: right!)
- path.addQuadCurve(to: CGPoint(x: 0, y: height), controlPoint: bottom!)
- path.addQuadCurve(to: CGPoint(x: 0, y: 0), controlPoint: left!)
- return path.cgPath
- }
- //штука чтобы перерисовать путь можно было
- private lazy var displayLink: CADisplayLink = {
- let displayLink = CADisplayLink(target: self, selector: #selector(self.updateLoop))
- displayLink.add(to: .current, forMode: RunLoopMode.commonModes)
- return displayLink
- }()
- //эту штука апдэйтит путь, чтобы красиво было
- @objc private func updateLoop() {
- elasticShape.path = bezierPathForControlPoints()
- }
- //запускает апдэйт
- private func startUpdateLoop() {
- displayLink.isPaused = false
- }
- //останавливает апдэйт
- private func stopDisplayLoop() {
- displayLink.isPaused = true
- }
- //сама анимашка вместе с новыми параметрами
- //usingSpringWithDamping насколько сильно будет шататься
- //initialSpringVelocity насколько долго
- //вроде как
- private func animateControlPoints() {
- UIView.animate(withDuration: 0.25,
- delay: 0,
- usingSpringWithDamping: 0.9,
- initialSpringVelocity: 1.5,
- options: [],
- animations: {
- self.topControlPointView.center.y -= self.contactForce
- self.rightControlPointView.center.x += self.contactForce
- self.bottomControlPointView.center.y += self.contactForce
- self.leftControlPointView.center.x -= self.contactForce
- }, completion: {_ in
- })
- }
- //начало анимации
- override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
- startUpdateLoop()
- animateControlPoints()
- }
- //конец анимации
- override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
- UIView.animate(withDuration: 0.45,
- delay: 0,
- usingSpringWithDamping: 0.15,
- initialSpringVelocity: 5.5,
- options: [],
- animations: {
- self.positionControlPoint()
- },
- completion: {_ in
- self.stopDisplayLoop()
- })
- }
- //чтобы вьха не мешала а заливкой служил сам шэйп
- override var backgroundColor: UIColor? {
- willSet{
- if let newValue = newValue {
- elasticShape.fillColor = newValue.cgColor
- super.backgroundColor = UIColor.clear
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement