使用 Button 触发的动画停止添加 onAppear 的 repeatForever 动画
Posted
技术标签:
【中文标题】使用 Button 触发的动画停止添加 onAppear 的 repeatForever 动画【英文标题】:Animation triggered using a Button stops a repeatForever animation added onAppear 【发布时间】:2020-10-13 11:49:20 【问题描述】:我想构建一个进度视图,看起来像一个随着进度增加而注满水的圆圈。
为此,我制作了一个自定义Shape
来创建水,并添加了一个动画,该动画将永远重复到Shape
上的波浪效果。
有了这个,我想在进度增加时添加一个动画来模拟水位增加。
问题是,当我触发最后一个动画时,它添加的动画 onAppear
停止工作。
有没有办法解决这个问题,所以两个动画都在结合,然后repeatForever
一个永远不会停止?
这是一个例子:
这是完整的代码:
struct WaterWaveView: View
@State var progress: CGFloat = 0.1
@State var phase: CGFloat = 0.5
var body: some View
VStack
WaterWave(progress: self.progress, phase: self.phase)
.fill(Color.blue)
.clipShape(Circle())
.frame(width: 250, height: 250)
.onAppear
withAnimation(Animation.linear(duration: 1)
.repeatForever(autoreverses: false))
self.phase = .pi * 2
Button("Add")
withAnimation(.easeOut(duration: 1))
self.progress += 0.1
Button("Reset")
self.progress = 0.0
struct WaterWave: Shape
var progress: CGFloat
let amplitude: CGFloat = 10
let waveLength: CGFloat = 20
var phase: CGFloat
var animatableData: AnimatablePair<CGFloat, CGFloat>
get AnimatablePair(phase, progress)
set
phase = newValue.first
progress = newValue.second
func path(in rect: CGRect) -> Path
var path = Path()
let width = rect.width
let height = rect.height
let midWidth = width / 2
let progressHeight = height * (1 - progress)
path.move(to: CGPoint(x: 0, y: progressHeight))
for x in stride(from: 0, to: width, by: 10)
let relativeX = x/waveLength
// let normalizedLength = relativeX / midWidth
let normalizedLength = (x - midWidth) / midWidth
let y = progressHeight + sin(phase + relativeX) * amplitude * normalizedLength
path.addLine(to: CGPoint(x: x, y: y))
path.addLine(to: CGPoint(x: width, y: progressHeight))
path.addLine(to: CGPoint(x: width, y: height))
path.addLine(to: CGPoint(x: 0, y: height))
path.addLine(to: CGPoint(x: 0, y: progressHeight))
return path
【问题讨论】:
这是否回答了您的问题***.com/a/63412977/12299030?changeValueOverTime
可能会有所帮助。然后你可以使用changeValueOverTime(value: self.$progress, newValue: self.progress + 0.1, duration: 1)
而不是调用withAnimation self.progress += 0.1
。
@Asperi 这在更改进度值时不使用动画,因此并不能真正解决我的问题。 @vacawama 嗯,它并没有真正起作用,因为我的值在我的真实代码库中的 ViewModel
中被修改了
【参考方案1】:
至少目前(SwiftUI 2.0)没有添加(累积)SwiftUI 动画。所以这是可能的解决方法。
使用 Xcode 12 / ios 14 测试
struct WaterWaveView: View
@State var progress: CGFloat = 0.1
@State var phase: CGFloat = 0.5
var body: some View
VStack
WaterWave(progress: self.progress, phase: self.phase)
.fill(Color.blue)
.clipShape(Circle())
.frame(width: 250, height: 250)
.animation(phase == 0 ? .default : Animation.linear(duration: 1).repeatForever(autoreverses: false), value: phase)
.animation(.easeOut(duration: 1), value: progress)
.onAppear
self.phase = .pi * 2
Button("Add")
self.phase = 0
self.progress += 0.1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2)
self.phase = .pi * 2
Button("Reset")
self.progress = 0.0
【讨论】:
谢谢,它有效,因为在我真正的最终用例中,值是从ViewModel
修改的将示例中的 Add 按钮操作的内容添加到 onChange
:)以上是关于使用 Button 触发的动画停止添加 onAppear 的 repeatForever 动画的主要内容,如果未能解决你的问题,请参考以下文章