IOS实现水波纹
需要实现一个水波纹效果
其实就是画两个正弦函数或者余弦函数的layer在view上面,根据屏幕刷新率来重绘,更新其左右偏移量来让其看起来是在左右移动
具体实现
- 定义两个layer,用不同的颜色填充
lazy var frontLayer: CAShapeLayer = {
let tempV = CAShapeLayer()
tempV.fillColor = frontColor.cgColor
return tempV
}()
lazy var backLayer: CAShapeLayer = {
let tempV = CAShapeLayer()
tempV.fillColor = backColor.cgColor
return tempV
}()
- 通过CADisplayLink来保持和屏幕相同的刷新率
lazy var displayLink: CADisplayLink = {
let tempV = CADisplayLink(target: self, selector: #selector(updateWave))
return tempV
}()
displayLink.add(to: RunLoop.main, forMode: .common)
CADisplayLink其实也就是一个和屏幕刷新频率相同的Timer,在每次屏幕刷新的时候就会调用传进去的Selector,初始化完成后需要通过.add方法加入到Runloop中
不用时销毁,调用invalidate()方法
displayLink.invalidate()
- 更新layer
在更新layer的updateWave
方法中将我们的线条画出来
复习一下正弦函数公式
y=Asin(ωx+φ)+ b
其中
- A: 曲线的振幅,曲线最高位和最低位的距离
- ω: 曲线的角速度,用于控制周期大小,越大宽越小
- φ: 曲线的初相,决定X轴的偏移量
- b: 曲线的偏距,决定Y轴的偏移量
在代码中
/// 速度
var speed: CGFloat = 0.01
/// 振幅,曲线最高位和最低位的距离
var amplitude: CGFloat = 10.0
/// 初相,曲线左右偏移量
var offsetX: CGFloat = 0.0
/// 角速度,用于控制周期大小,单位x中起伏的个数
var angularVelocity: CGFloat = 1.0
/// Y轴偏移量,偏距,曲线上下偏移量
var offsetY: CGFloat = 0.0
以前面这个layer为例
// 创建一个路径
let firstPath = CGMutablePath()
var firstY = bounds.size.width / 2
firstPath.move(to: CGPoint(x: 0, y: firstY))
for x in 0...Int(bounds.size.width) {
firstY = amplitude * sin(angularVelocity * CGFloat(x) + offsetX) + offsetY
firstPath.addLine(to: CGPoint(x: CGFloat(x), y: firstY))
}
firstPath.addLine(to: CGPoint(x: bounds.size.width, y: bounds.size.height))
firstPath.addLine(to: CGPoint(x: 0, y: bounds.size.height))
firstPath.closeSubpath()
frontLayer.path = firstPath
从0到以要绘制的宽度循环,绘制每一个像素点
在updateWave
方法中增加X轴偏移量,使其看起来在横向移动
offsetX += speed
第二个函数图像在增加X轴偏移量时和第一个区别一下,具体的细节调整可以根据需求来