Swift 3 中的动画曲线

Animated curve line in Swift 3

我想画一些贝塞尔曲线,我想用波浪效果为它们制作动画,

例子

你对我如何做到这一点有什么想法吗?贝塞尔线是最好的方法吗? 为此我只找到了 2 个库,但它们对我需要的东西并不是很有用,我尝试修改一个库的代码,不幸的是没有成功 https://github.com/yourtion/YXWaveView

我找到了这个库,https://antiguab.github.io/bafluidview/ 可以工作,但它是用 obj-c 编写的,也许你在 swift

中知道类似的东西

您可以使用 display link(一种针对屏幕刷新率优化的特殊计时器)来更改正在呈现的 path。显示 link 的处理程序应该计算已经过的时间量并相应地修改要呈现的路径。您可以使用 CAShapeLayer 来呈现路径,也可以使用自定义 UIView 子类。形状图层可能更容易:

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
    }
}

唯一棘手的部分是编写一个 wave 函数,该函数在特定时间产生 UIBezierPath 并随着时间的推移重复调用它时产生所需的效果。在这一个中,我正在渲染一条正弦曲线,其中振幅和偏移量根据生成路径时经过的时间而变化,但您可以在再现中做任何您想做的事情。希望这能说明基本思想。

以上代码产生: