To get your animation begin once more, you might want to reset section
worth earlier than begin animation. After WaveView
seem, section
worth get set to .pi * 2
, then while you press button, you simply set it to the identical worth, SwiftUI don’t see any change of section
so your animation just isn’t run, additionally when onChange
closure of isAnimating
get known as, a brand new withAnimation
block get known as due to this fact present animation repeatForever
get cancel as a result of animation
for section
and power
are stick collectively in AnimatablePair
:
personal func animateWave() {
section = 0 // <- reset section worth right here
withAnimation(Animation.linear(period: 2).repeatForever(autoreverses: false)) {
self.section = .pi * 2
}
}
You possibly can remark out withAnimation
block in onChange(of: isAnimating)
to maintain repeatForever
animation, however then you’ll not have animation when waveStrength
change:
.onChange(of: isAnimating) { _, newValue in
//withAnimation(.easeInOut(period: 0.5)) {
waveStrength = newValue ? 50.0 : 0.0
//}
if newValue {
animateWave()
}
}
One other repair is to seperate section
and waveStrength
from AnimatablePair
:
struct ShapheWave: View, @preconcurrency Animatable {
var power: Double
var frequency: Double
var section: Double
var animatableData: Double {
get { section }
set {
self.section = newValue
}
}
var physique: some View {
Wave(power: power, frequency: frequency, section: section)
.stroke(.black, lineWidth: 5)
}
}
struct Wave: Form {
var power: Double
var frequency: Double
var section: Double = .pi * 2
var animatableData: Double {
get { power }
set {
self.power = newValue
}
}
func path(in rect: CGRect) -> Path {
var path = Path()
let width = Double(rect.width)
let peak = Double(rect.peak)
let midHeight = peak / 2
let wavelength = width / frequency
let firstX = 0.0
let firstRelativeX = firstX / wavelength
let firstSine = sin(firstRelativeX + section)
let firstY = power * firstSine + midHeight
path.transfer(to: CGPoint(x: firstX, y: firstY))
for x in stride(from: 0.0, by: width, by: 1) {
let relativeX = x / wavelength
let sine = sin(relativeX + section)
let y = power * sine + midHeight
path.addLine(to: CGPoint(x: x, y: y))
}
return path
}
}
struct WaveView: View {
@Binding var isAnimating: Bool
@State personal var section = 0.0
@State personal var waveStrength = 50.0
var physique: some View {
VStack {
ShapheWave(power: waveStrength, frequency: 30, section: section)
.onChange(of: isAnimating) { _, newValue in
waveStrength = newValue ? 50.0 : 0.0
}
.onAppear {
animateWave()
}
.animation(.linear(period: 2).repeatForever(autoreverses: false), worth: section) .animation(.easeInOut(period: 0.5), worth: waveStrength)
}
}
personal func animateWave() {
section = .pi * 2
}
}