Swift 动画 —— Facebook 点赞动画

新建一个Swift工程。然后首先要做的就是画出动画的曲线。

画曲线

新建一个CurvedView 类

  class CurvedView: UIView {
        override func draw(_ rect: CGRect) {
            
        }
    }
复制代码

然后在viewDidLoad中创建一个CurvedView对象并且添加到view上。

   let curvedView = CurvedView(frame: view.frame)
        curvedView.backgroundColor = .yellow
        view.addSubview(curvedView)
复制代码

接下来要画曲线,先画两个点后运行,发现是一条很细的直线。

  override func draw(_ rect: CGRect) {
            let path = UIBezierPath()
            
            path.move(to: CGPoint(x: 0, y: 200))
            let endPoint = CGPoint(x: 200, y: 200)
            path.addLine(to:endPoint)
            path.stroke()
            
        }
复制代码

在这里插入图片描述 接下来要用到addCurve,在苹果官方文档中说到,此方法将当前点的三次贝塞尔曲线附加到终点参数指定的终点。这两个控制点定义了线段的曲率。看起来晕头转向的,写完代码后运行看的比较直观。

override func draw(_ rect: CGRect) {
            let path = UIBezierPath()
            
            path.move(to: CGPoint(x: 0, y: 200))
            let endPoint = CGPoint(x: 450, y: 200)
            path.lineWidth = 3
            let cp1 =  CGPoint(x: 100, y: 100)
            let cp2 =  CGPoint(x: 200, y: 300)
            path.addCurve(to: endPoint, controlPoint1: cp1, controlPoint2: cp2)
            path.stroke()
            
        }
复制代码

在这里插入图片描述

2. 添加动画

把画的UIBezierPath分离成一个方法,这样就方便我们使用

func customPath() -> UIBezierPath {
    let path = UIBezierPath()
    
    path.move(to: CGPoint(x: 0, y: 200))
    let endPoint = CGPoint(x: 450, y: 200)
    path.lineWidth = 3
    let cp1 =  CGPoint(x: 100, y: 100)
    let cp2 =  CGPoint(x: 200, y: 300)
    path.addCurve(to: endPoint, controlPoint1: cp1, controlPoint2: cp2)
    path.stroke()
    return path
}

class CurvedView: UIView {
    override func draw(_ rect: CGRect) {
        let path = customPath()
        path.lineWidth = 3
        path.stroke()
        
    }
}
复制代码

添加一张图片,并且将刚才的path赋值给animation,设置好动画时长等,然后将动画添加给图片。

        let imageView = UIImageView(image: UIImage(named: "heart"))
        imageView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
        let animation  = CAKeyframeAnimation(keyPath: "position")
        animation.path = customPath().cgPath
        animation.duration = 2
        animation.isRemovedOnCompletion = true
        animation.fillMode = .forwards
        animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
        imageView.layer.add(animation, forKey: nil)
        view.addSubview(imageView)
复制代码

接下来使用drand48给图片一个随机的大小。20 - 30

  let dimension = 20 + drand48() * 10
   imageView.frame = CGRect(x: 0, y: 0, width: dimension, height: dimension)
复制代码

为view 添加一个手势

 view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
复制代码

每次点击都生成十个imageView。

   @objc func handleTap() {
        (0...10).forEach { (_) in
            generateAnimatedViews()
        }
    }
    func generateAnimatedViews() {
        
        let imageView = UIImageView(image: UIImage(named: "heart"))
        let dimension = 20 + drand48() * 10
        imageView.frame = CGRect(x: 0, y: 0, width: dimension, height: dimension)
        let animation  = CAKeyframeAnimation(keyPath: "position")
        animation.path = customPath().cgPath
        animation.duration = 2
        animation.isRemovedOnCompletion = true
        animation.fillMode = .forwards
        animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
        imageView.layer.add(animation, forKey: nil)
        view.addSubview(imageView)
    }
复制代码

到这里有个问题就是每个图片的path都是一样的,所以会叠加到一起,所以需要调整一下path。 在customPath方法中给cp1 和cp2添加随机性。

   let randomYShift = 200 +  drand48() * 300
    let cp1 =  CGPoint(x: 100, y: 100 -  randomYShift)
    let cp2 =  CGPoint(x: 200, y: 300 + randomYShift)
复制代码

这里又发现了一个问题就是所有的图片都在一个X上面,这是因为它们的动画时长都一样,所以需要给动画时长页添加一点随机性。 在generateAnimatedViews方法中修改:

 animation.duration = 2 + drand48() * 3
复制代码

为了图片随机,在generateAnimatedViews方法中修改:

 let image = drand48() > 0.5 ? UIImage(named: "heart") :  UIImage(named: "thumbs_up")
  let imageView =  UIImageView(image: image)
复制代码

结束。完整代码如下: 在这里插入图片描述 在这里插入图片描述

猜你喜欢

转载自juejin.im/post/7014689160774549534