mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-24 20:00:37 +00:00
57 lines
2.5 KiB
Markdown
57 lines
2.5 KiB
Markdown
# 实现波浪动画
|
||
|
||
波浪的形状绘制在 CAShapeLayer 上。通过 CADisplayLink 与屏幕刷新频率同步,每次刷新都绘制新的波浪,并改变小船的位置和角度。另外,水和天空的颜色是渐变的,由 CAGradientLayer 实现,其中,显示水的 CAGradientLayer 需要有波浪形状的 CAShapeLayer 的遮罩\(mask\)。
|
||
|
||
### CAShapeLayer
|
||
|
||
CAShapeLayer 的属性 path \(CGPath\)就是图层要显示的形状。把波浪的形状绘制出来,赋值给此属性即可。
|
||
|
||
### CADisplayLink
|
||
|
||
创建 CADisplayLink,相应的 target 实现屏幕刷新时要调用的方法。把 CADisplayLink 加入 RunLoop 中。通过 isPaused 属性控制 CADisplayLink 是否暂停\(target 是否调用方法\)
|
||
|
||
```
|
||
private var waveLink: CADisplayLink?waveLink = CADisplayLink(target: self, selector: #selector(waveLinkRefresh))
|
||
waveLink?.isPaused = true
|
||
waveLink?.add(to: .current, forMode: .defaultRunLoopMode)
|
||
```
|
||
|
||
|
||
|
||
### 绘制波浪
|
||
|
||
波浪的形状关键是正弦函数曲线
|
||
|
||
```
|
||
y = A*sin(x+B)
|
||
```
|
||
|
||
参数 A 决定了波浪的高度;参数 B 决定了波浪在 x 轴的位置。
|
||
|
||
用一个属性 currentPhase 表示参数 B。每次屏幕刷新的时候用 currentPhase 绘制,然后更新此属性,加上一个固定的数。这样波浪就会朝左或右匀速移动。
|
||
|
||
为了使波浪高度逐渐变化,用一个属性表示参数 A,然后每次绘制后更新此属性,加上一个固定的数,直到波浪高度达到目标值。
|
||
|
||
### 小船的位置和旋转角度
|
||
|
||
已知小船 x 轴坐标,通过正弦函数可以直接计算出小船的 y 轴坐标。此外,小船需要随着波浪旋转,旋转至船底与波浪表面相切。这就要对正弦函数进行求导
|
||
|
||
```
|
||
y' = A * cos(x + B)
|
||
```
|
||
|
||
用以上式子计算出小船所在位置的 y',表示正弦函数在此处的切线斜率,几何意义是切线与 x 轴的夹角的正切值。反正切即可求出切线与 x 轴的夹角,也就是小船需要旋转的角度
|
||
|
||
```
|
||
angle = atan(y')
|
||
```
|
||
|
||
用以上旋转角度,改变小船视图\(UIView\)的 transform,调用 CGAffineTransformRotate 方法,实现小船的旋转。
|
||
|
||
### CAGradientLayer
|
||
|
||
CAGradientLayer 默认的颜色渐变方向是由上至下。给 colors 属性赋值一个包含 CGColor 的数组,则图层颜色由上至下,从数组第一个值经中间值渐变至最后一个值。
|
||
|
||
显示水的 CAGradientLayer 需要呈现波浪形状,需要 CAShapeLayer 的遮罩。把绘制好波浪形状的 CAShapeLayer 赋值给 CAGradientLayer 的 mask 属性即可。
|
||
|