I'm trying to write a view that displays 3 buttons, I cannot get the animation to start on load.
When a button is tapped, I want it to animate until either:
- it is tapped a second time
- another of the 3 buttons is tapped
I have got the code working using a @Environment object to store the running state. It toggles between the 3 buttons nicely:
The code for this is here:
struct ContentView : View {
@EnvironmentObject var model : ModelClockToggle
var body: some View {
VStack {
ForEach(0...2) { timerButton in
ActivityBreak(myId: timerButton)
.padding()
}
}
}
}
import SwiftUI
struct ActivityBreak : View {
var myId: Int
@EnvironmentObject var model : ModelClockToggle
let anim1 = Animation.basic(duration: 1.0, curve: .easeInOut).repeatCount(Int.max)
let noAni = Animation.basic(duration: 0.2, curve: .easeInOut).repeatCount(0)
var body: some View {
return Circle()
.foregroundColor(.red)
.scaleEffect(self.model.amIRunning(clock: self.myId) ? 1.0 : 0.6)
.animation( self.model.amIRunning(clock: self.myId) ? anim1 : noAni )
.tapAction {
self.model.toggle(clock: self.myId)
}
}
}
For completeness, the model is:
import Foundation
import SwiftUI
import Combine
class ModelClockToggle: BindableObject {
let didChange = PassthroughSubject<ModelClockToggle, Never>()
private var clocksOn: [Bool] = [false,false,false]
init() {
clocksOn = []
clocksOn.append(UserDefaults.standard.bool(forKey: "toggle1"))
clocksOn.append(UserDefaults.standard.bool(forKey: "toggle2"))
clocksOn.append(UserDefaults.standard.bool(forKey: "toggle3"))
debugPrint(clocksOn)
}
func toggle(clock: Int) {
debugPrint(#function)
if clocksOn[clock] {
clocksOn[clock].toggle()
} else {
clocksOn = [false,false,false]
clocksOn[clock].toggle()
}
saveState()
didChange.send(self)
}
func amIRunning(clock: Int) -> Bool {
debugPrint(clocksOn)
return clocksOn[clock]
}
private func saveState() {
UserDefaults.standard.set(clocksOn[0], forKey: "toggle1")
UserDefaults.standard.set(clocksOn[1], forKey: "toggle2")
UserDefaults.standard.set(clocksOn[2], forKey: "toggle3")
}
}
How do I make the repeating animation start at load time based on the @Environment object I have passed into the View? Right now SwiftUI only seems to consider state change once the view is loaded.
I tried adding an .onAppear modifier, but that meant I had to use a different animator - which had very strange effects.
help gratefully received.