SwiftUI-使用不同曲线设置多个参数的动画

SwiftUI-使用不同曲线设置多个参数的动画,swiftui,Swiftui,我正在SwiftUI视图中探索正弦波渲染,并已将我的视图构建为具有3个可控参数: 阶段(控制偏移并允许“水平”设置动画) 振幅(控制每个峰值的高度) 频率(有多少完整波) 以下是一个屏幕截图: 我的正弦波被实现为形状,因此它已经是可动画的。我制作了振幅和频率一对AnimatablePair并将其作为我的形状的可设置动画的数据公开如下: var animatableData: AnimatablePair<CGFloat, CGFloat> { get { .init(f

我正在SwiftUI
视图中探索正弦波渲染,并已将我的视图构建为具有3个可控参数:

  • 阶段
    (控制偏移并允许“水平”设置动画)
  • 振幅
    (控制每个峰值的高度)
  • 频率
    (有多少完整波)
以下是一个屏幕截图:

我的
正弦波
被实现为
形状
,因此它已经是
可动画的
。我制作了
振幅
频率
一对
AnimatablePair
并将其作为我的形状的
可设置动画的
数据公开如下:

var animatableData: AnimatablePair<CGFloat, CGFloat> {
    get { .init(frequency, amplitude) }
    set {
        frequency = newValue.first
        amplitude = newValue.second
    }
}
现在我还想给
阶段设置动画。但我不想让这辆车自动倒车,我希望它能快得多。不幸的是,在这个块旁边添加另一个带有动画的
块没有效果,即使我将它作为可设置动画的数据的一部分。最后一个动画块始终获胜

我应该如何处理希望使用两个不同的
动画
实例为两个属性设置动画的问题?

以下是可能的方法(scratchy)。假设您将可设置动画的一对组合到结构中,并将其作为单个值使用,则可以使用
.animation(\uu,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)
    }
                

这看起来很有希望,但不幸的是,我无法用这段代码让它产生动画效果。值参数似乎只是用作何时应用动画的触发器,但不一定使用该值来插值所使用的值。我的理解很可能有缺陷,但在任何情况下,当使用这种方法时,我都无法使其动画化。因此,如果这些值有不同的动画,这种方法非常有用——但在我的例子中,我希望两者同时动画化。使用此方法,最后一个动画将覆盖任何当前动画。最后,我改变了我的动画,使振幅和频率像这样一起被动画化,相位被一个计时器分别控制。将这个答案标记为正确,因为它帮助我走上了正确的道路。
@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)
    }