UIBezierPath
,就像这个链接所展示的。
https://dribbble.com/shots/3994990-Waves-Loading-Animation
我将这个动画用作数据点(0-100)的折线图。我已经成功地绘制了路径,但是在正确地进行动画方面遇到了麻烦。目前看起来像这样:https://imgur.com/a/QQX4DGo,运动非常生硬/快速。
let dataPoints: [Double]
var displayLink: CADisplayLink?
var startTime: CFAbsoluteTime?
let background: UIView = {
let view = UIView()
return view
}()
let shapeLayer: CAShapeLayer = {
let layer = CAShapeLayer()
return layer
}()
init(frame: CGRect, data: [Double], precip: [String]) {
self.dataPoints = data
super.init(frame: frame)
addSubview(background)
background.anchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}
override func layoutSubviews() {
super.layoutSubviews()
background.layer.addSublayer(shapeLayer)
shapeLayer.strokeColor = UIColor.waterColor.cgColor
shapeLayer.fillColor = UIColor.waterColor.cgColor
startDisplayLink()
}
func wave(at elapsed: Double) -> UIBezierPath {
let maxX = bounds.width
let maxY = bounds.height
func f(_ y: Double) -> CGFloat {
let random = CGFloat.random(in: 1.0...5.0)
return CGFloat(y) + sin(CGFloat(elapsed/2) * random * .pi)
}
func z(_ x: CGFloat) -> CGFloat {
let random = CGFloat.random(in: 1.0...2.0)
let position = Int.random(in: 0...1)
if(position == 0) {
return x + random
} else {
return x - random
}
}
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: maxY))
let steps = bounds.width/CGFloat(24)
var start: CGFloat = steps
for i in 0..<24 {
let x = z(start)
let y = maxY - f(dataPoints[i]*100)
let point = CGPoint(x: x, y: y)
path.addLine(to: point)
start+=steps
}
path.close()
return path
}
func startDisplayLink() {
startTime = CFAbsoluteTimeGetCurrent()
displayLink?.invalidate()
displayLink = CADisplayLink(target: self, selector:#selector(handleDisplayLink(_:)))
displayLink?.add(to: .current, forMode: .common)
displayLink?.preferredFramesPerSecond = 11
}
func stopDisplayLink() {
displayLink?.invalidate()
displayLink = nil
}
@objc func handleDisplayLink(_ displayLink: CADisplayLink) {
let elapsed = CFAbsoluteTimeGetCurrent() - startTime!
shapeLayer.path = wave(at: elapsed).cgPath
}
f
设为两个不同正弦曲线的和(例如,可能是这个第二个正弦曲线具有较小的振幅但更长的周期)。根据周期、振幅等的不同,你可以得到各种各样的变化。例如,这里有一个微妙的例子:https://gist.github.com/robertmryan/427e7d4d74f4c4e878c8755e68fd9d13 - Rob