这里会使用到正弦函数进行计算:y=Asin(ωx+φ)。忘了的可以回去补补课了😆.我不会告诉你们我也回去补了课😂.
正弦型函数解析式:y=Asin(ωx+φ)
各常数值对函数图像的影响:
φ(初相位):决定波形与X轴位置关系或横向移动距离(左加右减)
ω:决定周期(最小正周期T=2π/|ω|)
A:决定峰值(即纵向拉伸压缩的倍数)
h:表示波形在Y轴的位置关系或纵向移动距离(上加下减)
下面看一下代码吧.
class JZWaveProgress: UIView {
/** 进度 0-1 **/
var progress: CGFloat! {
didSet {
y = bounds.height * (1 - progress)
stopAnimation()
startAnimation()
}
}
/** 颜色 **/
var waveColor: UIColor! = UIColor(colorLiteralRed: (34 / 255.0), green: (116 / 255.0), blue: (210 / 255.0), alpha: 1) {
didSet {
layer.borderColor = waveColor.cgColor
layer.borderWidth = 1
}
}
/** 波峰 **/
var waveCrest: CGFloat? = 5.0
/** 进度 **/
var text: String? {
didSet {
textLabel.text = text!
}
}
var font: UIFont? {
didSet {
textLabel.font = font
textLabel.frame.size.height = (font?.pointSize)!
textLabel.frame.origin.y = self.bounds.midY - textLabel.frame.height * 0.5
}
}
var textColor: UIColor? {
didSet {
textLabel.textColor = textColor
}
}
var speed: CGFloat! = 1
fileprivate var y: CGFloat!
fileprivate var offset: CGFloat! = 0
fileprivate var timer: CADisplayLink!
fileprivate lazy var waveLayer: CAShapeLayer = {
let waveLayer = CAShapeLayer()
waveLayer.frame = self.bounds
waveLayer.fillColor = self.waveColor.cgColor
self.layer.addSublayer(waveLayer)
return waveLayer
}()
fileprivate lazy var textLabel: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: 17))
label.textAlignment = .center
label.frame.origin.y = self.bounds.midY - label.frame.height * 0.5
self.addSubview(label)
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
let wh = min(frame.width, frame.height)
bounds = CGRect(x: 0, y: 0, width: wh, height: wh)
y = bounds.height
layer.cornerRadius = wh * 0.5
layer.masksToBounds = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension JZWaveProgress {
fileprivate func startAnimation() {
let timer = CADisplayLink(target: self, selector: #selector(waveAnimation))
self.timer = timer
timer.add(to: RunLoop.main, forMode: .commonModes)
}
fileprivate func stopAnimation() {
timer?.invalidate()
timer = nil
}
@objc fileprivate func waveAnimation() {
// 设置没有波纹
if progress == 0.0 || progress == 1.0 {
speed = 0
}
offset = offset + speed
// firstWave: y=Asin(ωx+φ) + h
let firstWave = CGMutablePath()
let cycle = Double(offset * CGFloat(Float.pi) * 2 / bounds.width)
let width = bounds.width
let height = bounds.height
let startOffSetY = waveCrest! * CGFloat(sin(cycle))
var originOffSetY: CGFloat = 0
firstWave.move(to: CGPoint(x: 0, y: startOffSetY))
for i in 0...Int(floorf(Float(bounds.width))) {
originOffSetY = waveCrest! * CGFloat(sin(cycle + Double.pi * 2 / Double(width) * Double(i))) + y
firstWave.addLine(to: CGPoint(x: CGFloat(i), y: originOffSetY))
}
firstWave.addLine(to: CGPoint(x: width, y: originOffSetY))
firstWave.addLine(to: CGPoint(x: width, y: height))
firstWave.addLine(to: CGPoint(x: 0, y: height))
firstWave.addLine(to: CGPoint(x: 0, y: startOffSetY))
firstWave.closeSubpath()
waveLayer.path = firstWave
waveLayer.fillColor = waveColor.cgColor
bringSubview(toFront: textLabel)
}
}
ps: 如果需要条波纹的话,多加几条 path 就好了,前提是不要让初相位一样哦