问题
I want to build a progress view that look like a circle that fills with water as the progress increase.
To do that, I've made a custom Shape
that create the water and I added an Animation that repeat forever to a wave effect on that Shape
.
With that I wanted to add an animation while the progress increase to simulate that the water level increases.
The problem is that when I trigger this last animation, the one that it's added onAppear
stop working.
Is there a way to fix that so both animation are combining then the repeatForever
one never stops ?
Here is an example :
And here is the full code :
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
}
}
回答1:
SwiftUI animations are not added(cumulated), at least for now (SwiftUI 2.0). So here is possible workaround.
Tested with 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
}
}
}
}
来源:https://stackoverflow.com/questions/64334667/animation-triggered-using-a-button-stops-a-repeatforever-animation-added-onappea