我有以下用户界面:
Red Rectangle
旋转速度以滑块的值为基础。我使用.linear(duration:).repeatForever(autoreverses: false)
(持续时间以滑块的值为基础)和.id
修改器来实现此目的,以便在滑块的值发生变化时停止当前动画。
struct ContentView: View {
@State private var level: Double = 0
@State private var rotation: Double = 0
var body: some View {
VStack(spacing: 16) {
Rectangle().fill(.red)
.frame(width: 100, height: 100)
.id(level)
.rotationEffect(Angle(degrees: rotation))
.animation(level > 0 ? .linear(duration: 2 / level).repeatForever(autoreverses: false) : .linear(duration: 2), value: rotation)
Spacer().frame(height: 12)
Slider(value: $level, in: 0...3, step: 1)
HStack {
Text("0")
.fontWeight(.semibold)
Spacer()
Text("1")
.fontWeight(.semibold)
Spacer()
Text("2")
.fontWeight(.semibold)
Spacer()
Text("3")
.fontWeight(.semibold)
}
}
.padding(16)
.onChange(of: level, perform: { _ in
rotation += 360
})
}
}
我当前的问题是当用户更改滑块的值时,Rectangle
会重置为初始状态,因此.id
会产生故障。
以下是我的代码当前如何工作的视频链接: https: //imgur.com/a/6bsUJzm
我的问题是当用户更改滑块的值时,如何实现状态之间的平滑过渡?任何见解或建议都将不胜感激!
修复的一个方法是避免使用
.repeatForever
动画。相反:从 iOS 17 开始,使用 触发的动画
withAnimation
可以有completion
回调。因此,这将是触发后续动画的一种方法。但是,这样做会产生相当卡顿的动画。另一种方法是使用
Animatable
ViewModifier
跟踪动画并在动画完成时执行操作。这样做更顺畅。SwiftUI Animation 完成动画循环的答案提供了一个可用于此目的的通用修饰符(这是我的答案)。那篇文章也涉及连续旋转,所以这是一个相当类似的问题。以下是更新后的示例。更多说明:
.id
应删除该修饰符。动画修改器出现在 之后,这一点很重要
AnimationCompletionCallback
。由于
.repeatForever
不再使用,动画修改器可以简化(不需要三元运算符)。.fontWeight
将滑块标签的应用于HStack
而不是应用于每个单独的标签更加简单。您之前使用的是已弃用的版本
.onChange
。如果您实际上的目标是 iOS 17 之前的 iOS 版本,请使用下面代码中提供的注释版本。