SwiftUI-使用不同曲线对多个参数进行动画处理

时间:2020-06-29 03:22:25

标签: swiftui

我正在探索SwiftUI View中的正弦波渲染,并建立了具有3个可控参数的视图:

  • phase(控制偏移量并允许“水平”设置动画)
  • amplitude(控制每个峰的高度)
  • frequency(有多少个完整的波浪)

以下是屏幕截图:

enter image description here

我的SineWave被实现为Shape,因此它已经是Animatable。我将amplitudefrequency设为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实例为两个属性设置动画的问题?

1 个答案:

答案 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)
    }