Animated curve line in Swift 3

前端 未结 1 1871
青春惊慌失措
青春惊慌失措 2021-01-31 13:16

I want to draw some bezier lines and I want to animate them with a wave effect,

Example

Do you have some ideas about how I can do this ? Bezier line is it the b

1条回答
  •  不思量自难忘°
    2021-01-31 13:24

    You can use a display link, a special kind of timer optimized for screen refresh rates, to change the path that is being rendered. The handler for the display link should calculate the amount of time that has elapsed and modify the path to be rendered accordingly. You can either use a CAShapeLayer to render the path, or you can use a custom UIView subclass. The shape layer is probably easier:

    class ViewController: UIViewController {
    
        private weak var displayLink: CADisplayLink?
        private var startTime: CFTimeInterval = 0
    
        /// The `CAShapeLayer` that will contain the animated path
    
        private let shapeLayer: CAShapeLayer = {
            let shapeLayer = CAShapeLayer()
            shapeLayer.strokeColor = UIColor.white.cgColor
            shapeLayer.fillColor = UIColor.clear.cgColor
            shapeLayer.lineWidth = 3
            return shapeLayer
        }()
    
        // start the display link when the view appears
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            view.layer.addSublayer(shapeLayer)
            startDisplayLink()
        }
    
        // Stop it when it disappears. Make sure to do this because the
        // display link maintains strong reference to its `target` and
        // we don't want strong reference cycle.
    
        override func viewDidDisappear(_ animated: Bool) {
            super.viewDidDisappear(animated)
            stopDisplayLink()
        }
    
        /// Start the display link
    
        private func startDisplayLink() {
            startTime = CACurrentMediaTime()
            self.displayLink?.invalidate()
            let displayLink = CADisplayLink(target: self, selector:#selector(handleDisplayLink(_:)))
            displayLink.add(to: .main, forMode: .common)
            self.displayLink = displayLink
        }
    
        /// Stop the display link
    
        private func stopDisplayLink() {
            displayLink?.invalidate()
        }
    
        /// Handle the display link timer.
        ///
        /// - Parameter displayLink: The display link.
    
        @objc func handleDisplayLink(_ displayLink: CADisplayLink) {
            let elapsed = CACurrentMediaTime() - startTime
            shapeLayer.path = wave(at: elapsed).cgPath
        }
    
        /// Create the wave at a given elapsed time.
        ///
        /// You should customize this as you see fit.
        ///
        /// - Parameter elapsed: How many seconds have elapsed.
        /// - Returns: The `UIBezierPath` for a particular point of time.
    
        private func wave(at elapsed: Double) -> UIBezierPath {
            let elapsed = CGFloat(elapsed)
            let centerY = view.bounds.midY
            let amplitude = 50 - abs(elapsed.remainder(dividingBy: 3)) * 40
    
            func f(_ x: CGFloat) -> CGFloat {
                return sin((x + elapsed) * 4 * .pi) * amplitude + centerY
            }
    
            let path = UIBezierPath()
            let steps = Int(view.bounds.width / 10)
    
            path.move(to: CGPoint(x: 0, y: f(0)))
            for step in 1 ... steps {
                let x = CGFloat(step) / CGFloat(steps)
                path.addLine(to: CGPoint(x: x * view.bounds.width, y: f(x)))
            }
    
            return path
        }
    }
    

    The only tricky part is writing a wave function that yields a UIBezierPath for a particular time and yields the desired effect when you call it repeatedly as time passes. In this one, I'm rendering a sine curve, where the amplitude and the offset vary based upon the time that has elapsed at the point that the path is generated, but you can do whatever you want in your rendition. Hopefully this illustrates the basic idea.

    The above code yields:

    0 讨论(0)
提交回复
热议问题