Consider this code in which I'm trying to continuously animate a set of circles from red to blue:
struct ContentView: View {
let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
@State var colorOn = false
var body: some View {
VStack {
ForEach(0...10, id: \.self) { n in
CircleView(size: 30, isOn: n%2 == 0 ? $colorOn : !$colorOn)
.onReceive(timer) { _ in
colorOn.toggle()
}
}
}
}
}
#Preview {
ContentView()
}
struct CircleView: View {
var size: CGFloat
@Binding var isOn: Bool
var body: some View {
ZStack {
Circle()
.fill(isOn ? .red : .blue)
.frame(width: size, height: size)
.animation(.easeInOut(duration: 0.5), value: isOn)
}
}
}
The trick is that I need them to alternate colors, as in every other circle should be red while the ones in between are blue. But I can't get the syntax right on the @Bindable property:
Cannot convert value '$colorOn' of type 'Binding<Bool>' to expected type 'Bool', use wrapped value instead
A @Binding
property means that the value actually comes from somewhere else and can be shared with other places. It create a two way binding between the view (CircleView), and the stored data (in this case is @State var colorOn
in ContentView
).
It was correct if inside CircleView
, you also had an action that could modify isOn
such as:
struct CircleView: View {
@Binding var isOn: Bool
var body: some View {
ZStack {
Circle()
...
.onTapGeture {
//Stop animation immediately
//It will impact to `colorOn` in `ContentView`
isOn = false
}
}
}
}
However, your purpose is to swap colors every single second, depending on the timer. So, you have nothing to do with @Binding since the CircleView is used only for displaying data. You just need to define a Bool
that represents its on/off states.
struct CircleView: View {
var size: CGFloat
var isOn: Bool //<- Remove binding here
var body: some View {
ZStack {
Circle()
.fill(isOn ? .red : .blue)
.frame(width: size, height: size)
.animation(.easeInOut(duration: 0.5), value: isOn)
}
}
}
The last step is to remove Binding ($) from ContentView then you're good to go.
struct ContentView: View {
@State private var colorOn = false
var body: some View {
...
CircleView(size: 30, isOn: n % 2 == 0 ? colorOn : !colorOn)
...
}
}
Output