Animated curve line in Swift 3

我的未来我决定 提交于 2019-12-20 09:07:19

问题


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 best method to do it ? I found only 2 libs for this, but they are not really useful for what I need, I try to modify the code of one lib, unfortunately without success https://github.com/yourtion/YXWaveView

I found this lib, https://antiguab.github.io/bafluidview/ which does the work, but it written in obj-c, maybe you know something like this in swift



回答1:


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 var displayLink: CADisplayLink?
    private var startTime: CFAbsoluteTime?

    /// The `CAShapeLayer` that will contain the animated path

    private let shapeLayer: CAShapeLayer = {
        let _layer = CAShapeLayer()
        _layer.strokeColor = UIColor.white.cgColor
        _layer.fillColor = UIColor.clear.cgColor
        _layer.lineWidth = 3
        return _layer
    }()

    // start the display link when the view appears

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        view.layer.addSublayer(shapeLayer)

        self.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) {
        stopDisplayLink()
    }

    /// Start the display link

    private func startDisplayLink() {
        startTime = CFAbsoluteTimeGetCurrent()
        displayLink?.invalidate()
        displayLink = CADisplayLink(target: self, selector:#selector(handleDisplayLink(_:)))
        displayLink?.add(to: RunLoop.current, forMode: .commonModes)
    }

    /// Stop the display link

    private func stopDisplayLink() {
        displayLink?.invalidate()
        displayLink = nil
    }

    /// Handle the display link timer.
    ///
    /// - Parameter displayLink: The display link.

    func handleDisplayLink(_ displayLink: CADisplayLink) {
        let elapsed = CFAbsoluteTimeGetCurrent() - 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 centerY = view.bounds.height / 2
        let amplitude = CGFloat(50) - fabs(fmod(CGFloat(elapsed), 3) - 1.5) * 40

        func f(_ x: Int) -> CGFloat {
            return sin(((CGFloat(x) / view.bounds.width) + CGFloat(elapsed)) * 4 * .pi) * amplitude + centerY
        }

        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: f(0)))
        for x in stride(from: 0, to: Int(view.bounds.width + 9), by: 10) {
            path.addLine(to: CGPoint(x: CGFloat(x), 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:



来源:https://stackoverflow.com/questions/44006942/animated-curve-line-in-swift-3

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!