• Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Create a new Swift project. And then the first thing to do is draw the curve of the animation.

Draw the curve

Create a new CurvedView class

  class CurvedView: UIView {
        override func draw(_ rect: CGRect) {
            
        }
    }
Copy the code

Then create a CurvedView object in viewDidLoad and add it to the view.

   let curvedView = CurvedView(frame: view.frame)
        curvedView.backgroundColor = .yellow
        view.addSubview(curvedView)
Copy the code

Now I’m going to draw a curve, and I’m going to draw two points and then I’m going to run, and I’m going to find a very thin line.

  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()
            
        }
Copy the code

The next step is to use addCurve, which, according to the official apple documentation, appends the cubic bezier curve of the current point to the endpoint specified by the endpoint parameter. These two control points define the curvature of the line segment. Looks confused, after writing the code to run to see more intuitive.

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()
            
        }
Copy the code

2. Add animations

Separate the drawn UIBezierPath into a method so we can use it easily

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()
        
    }
}
Copy the code

Add an image, assign the previous path to the animation, set the animation duration, etc., and then add the animation to the image.

        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)
Copy the code

Next use drand48 to give the image a random size. 20-30

  let dimension = 20 + drand48() * 10
   imageView.frame = CGRect(x: 0, y: 0, width: dimension, height: dimension)
Copy the code

Add a gesture to the view

 view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
Copy the code

Ten ImageViews are generated per click.

@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) }Copy the code

The problem here is that every image has the same path, so it adds up, so you need to adjust the path. Add randomness to cp1 and cp2 in the customPath method.

   let randomYShift = 200 +  drand48() * 300
    let cp1 =  CGPoint(x: 100, y: 100 -  randomYShift)
    let cp2 =  CGPoint(x: 200, y: 300 + randomYShift)
Copy the code

Another problem here is that all the images are above an X, because they all have the same animation duration, so we need to add a bit of randomness to the animation duration page. In the generateAnimatedViews method:

 animation.duration = 2 + drand48() * 3
Copy the code

To randomize the image, modify it in the generateAnimatedViews method:

Let image = drand48() > 0.5? UIImage(named: "heart") : UIImage(named: "thumbs_up") let imageView = UIImageView(image: image)Copy the code

The end. The complete code is as follows: