如何在 SwiftUI 中停止笔划重复动画
How to stop a stroke repeat animation in SwiftUI
如何通过赋值绑定来控制Rectangle
动画重复与否属性isRepeatAnimation
?
我期望的是,在将 true
分配给 isRepeatAnimation
后,边框宽度从 5.0 到 0.0 来回动画,并且在分配 false
后重复动画关闭至 isRepeatAnimation
.
import SwiftUI
struct ContentView: View {
@Binding var isRepeatAnimation: Bool
@State var lineWidth: CGFloat = 5
var body: some View {
Rectangle()
.stroke(Color.blue, style: StrokeStyle(lineWidth: lineWidth))
.frame(width: 100, height: 100)
.animation(isRepeatAnimation ? repeatAnimation : Animation.easeInOut, value: lineWidth)
}
var repeatAnimation: Animation {
Animation.easeInOut.repeatForever(autoreverses: true)
}
}
struct ContentViewPreviewer: View {
@State var repeated = false
var body: some View {
VStack {
ContentView(isRepeatAnimation: $repeated)
Button("Toggle") {
repeated.toggle()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentViewPreviewer()
}
}
要停止重复动画,我们应该将其替换为默认动画,并且可以切换线宽。
测试 Xcode 13.4 / iOS 15.4
主要修复如下:
Rectangle()
.stroke(Color.blue, style: StrokeStyle(lineWidth: isRepeatAnimation ? 0 : lineWidth))
.frame(width: 100, height: 100)
.animation(isRepeatAnimation ? repeatAnimation : Animation.default, value: isRepeatAnimation)
如果目的是让线宽从5到0再到5然后停止,这可以是一个解决方案。如果目的是手动停止动画,请阅读 Asperi 的解决方案。
您可以设置两次动画,首先是在持续时间的前半段将线宽从 5 更改为 0,然后在后半段从 0 更改为 5。您可以使用两个命令控制此行为:
- 在
.animation()
上,包含一个 pre-defined (duration:)
- 布尔变量发生变化时,使用
DispatchQueue.main.asyncAfter()
从 0 变回 5
示例代码如下:
struct ContentView: View {
@Binding var animate: Bool
@State private var lineWidth = 5.0
var body: some View {
Rectangle()
.stroke(Color.blue, style: StrokeStyle(lineWidth: lineWidth))
// Instead of repeating, make it with a pre-defined duration.
// The value here (0.25) is half of the total duration
.animation(.easeInOut(duration: 0.25), value: lineWidth)
.frame(width: 100, height: 100)
// Change the line width when animate changes
.onChange(of: animate) { _ in
// Make it zero immediately
lineWidth = 0
// On the second half of the duration, make it 5 again
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
lineWidth = 5
}
}
}
}
struct ContentViewPreviewer: View {
@State var animate = false
var body: some View {
VStack {
ContentView(animate: $animate)
Button("Toggle") {
animate.toggle()
}
}
}
}
如何通过赋值绑定来控制Rectangle
动画重复与否属性isRepeatAnimation
?
我期望的是,在将 true
分配给 isRepeatAnimation
后,边框宽度从 5.0 到 0.0 来回动画,并且在分配 false
后重复动画关闭至 isRepeatAnimation
.
import SwiftUI
struct ContentView: View {
@Binding var isRepeatAnimation: Bool
@State var lineWidth: CGFloat = 5
var body: some View {
Rectangle()
.stroke(Color.blue, style: StrokeStyle(lineWidth: lineWidth))
.frame(width: 100, height: 100)
.animation(isRepeatAnimation ? repeatAnimation : Animation.easeInOut, value: lineWidth)
}
var repeatAnimation: Animation {
Animation.easeInOut.repeatForever(autoreverses: true)
}
}
struct ContentViewPreviewer: View {
@State var repeated = false
var body: some View {
VStack {
ContentView(isRepeatAnimation: $repeated)
Button("Toggle") {
repeated.toggle()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentViewPreviewer()
}
}
要停止重复动画,我们应该将其替换为默认动画,并且可以切换线宽。
测试 Xcode 13.4 / iOS 15.4
主要修复如下:
Rectangle()
.stroke(Color.blue, style: StrokeStyle(lineWidth: isRepeatAnimation ? 0 : lineWidth))
.frame(width: 100, height: 100)
.animation(isRepeatAnimation ? repeatAnimation : Animation.default, value: isRepeatAnimation)
如果目的是让线宽从5到0再到5然后停止,这可以是一个解决方案。如果目的是手动停止动画,请阅读 Asperi 的解决方案。
您可以设置两次动画,首先是在持续时间的前半段将线宽从 5 更改为 0,然后在后半段从 0 更改为 5。您可以使用两个命令控制此行为:
- 在
.animation()
上,包含一个 pre-defined(duration:)
- 布尔变量发生变化时,使用
DispatchQueue.main.asyncAfter()
从 0 变回 5
示例代码如下:
struct ContentView: View {
@Binding var animate: Bool
@State private var lineWidth = 5.0
var body: some View {
Rectangle()
.stroke(Color.blue, style: StrokeStyle(lineWidth: lineWidth))
// Instead of repeating, make it with a pre-defined duration.
// The value here (0.25) is half of the total duration
.animation(.easeInOut(duration: 0.25), value: lineWidth)
.frame(width: 100, height: 100)
// Change the line width when animate changes
.onChange(of: animate) { _ in
// Make it zero immediately
lineWidth = 0
// On the second half of the duration, make it 5 again
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
lineWidth = 5
}
}
}
}
struct ContentViewPreviewer: View {
@State var animate = false
var body: some View {
VStack {
ContentView(animate: $animate)
Button("Toggle") {
animate.toggle()
}
}
}
}