我正在探索SwiftUI View
中的正弦波渲染,并建立了具有3个可控参数的视图:
phase
(控制偏移量并允许“水平”设置动画)amplitude
(控制每个峰的高度)frequency
(有多少个完整的波浪)以下是屏幕截图:
我的SineWave
被实现为Shape
,因此它已经是Animatable
。我将amplitude
和frequency
设为AnimatablePair
,并将其作为形状的animatable
数据公开,如下所示:
var animatableData: AnimatablePair<CGFloat, CGFloat> {
get { .init(frequency, amplitude) }
set {
frequency = newValue.first
amplitude = newValue.second
}
}
这有效,如果在包含视图中执行此操作,我会得到一个不错的动画:
SineWaveShape(phase: phase, amplitude: amplitude, frequency: frequency)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round))
.foregroundColor(.red)
.onAppear {
withAnimation(Animation.spring(response: 0.5, dampingFraction: 0.4, blendDuration: 0.1).repeatForever()) {
amplitude = 0.1
frequency = 4
}
}
现在我也想为phase
设置动画。但是我不希望这个自动反转,我希望它更快。不幸的是,即使我将其作为可动画数据的一部分,在该块旁边添加另一个withAnimation
块也无效。最后一个动画块总是获胜。
我应该如何解决要用两个不同的Animation
实例为两个属性设置动画的问题?
答案 0 :(得分:1)
这是可能的方法(抓痒的)。假设您将可设置动画的对组合为struct并将其作为单个值使用,则可以使用.animation(_, value:)
为每个值指定专用动画:
@State private var pair: CGSize = .zero
@State private var phase: CGFloat = .zero
...
SineWaveShape(phase: phase, amplitude: amplitude, frequency: frequency)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round))
.foregroundColor(.red)
.animation(Animation.linear(duration: 5).repeatForever(), value: phase)
.animation(Animation.spring(response: 0.5, dampingFraction: 0.4, blendDuration: 0.1).repeatForever(), value: pair)
.onAppear {
self.phase = 90
self.pair = CGSize(width: 0.1, height: 4)
}