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
并随着时间的推移重复调用它时产生所需的效果。在这一个中,我正在渲染一条正弦曲线,其中振幅和偏移量根据生成路径时经过的时间而变化,但您可以在再现中做任何您想做的事情。希望这能说明基本思想。
以上代码产生:
我想画一些贝塞尔曲线,我想用波浪效果为它们制作动画,
例子
你对我如何做到这一点有什么想法吗?贝塞尔线是最好的方法吗? 为此我只找到了 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
并随着时间的推移重复调用它时产生所需的效果。在这一个中,我正在渲染一条正弦曲线,其中振幅和偏移量根据生成路径时经过的时间而变化,但您可以在再现中做任何您想做的事情。希望这能说明基本思想。
以上代码产生: