0
votes

I've been trying to use the ternary operator in SwiftUI to make some view modifiers "dynamic" based on the value of a @State var I declared. But, seems like SwiftUI doesn't fully support this operator inside view modifiers. Is it a bug? What am I missing here?

struct Test: View {
    @State var selectedIdx: Int?
    var colors : [Color] = [.red, .orange, .yellow, .green, .blue]

    var body: some View {
        VStack {
            //some other views that change "selectedIdx" (the @State var)
            //...
            ForEach(0..<colors.count) { idx in
                Rectangle()
                    .frame(width: 70, height: 100)
                    //some other view modifiers that will be animated
                    .animation(Animation.easeInOut.delay(self. selectedIdx == nil ? 0.1*Double(self.colors.count - idx) : 0.1*Double(idx)))
            }
        }
    }
}

The error disappears if I remove the ternary operator. I have tried different combinations for the ternary operator but none of them work:

.animation(Animation.easeInOut.delay(0.1*Double(self.selectedIdx == nil ? self.colors.count - idx : idx)))

.animation(Animation.easeInOut.delay(self.selectedIdx == nil ? 0.1*Double(self.colors.count - idx) : Double(idx)))

And even something simple like the following, doesn't work:

.animation(Animation.easeInOut.delay(self.selectedIdx == nil ? Double(idx) : Double(idx)))

Any ideas about the correct use of the ternary operator inside view modifiers?

2
There is no selectedIdx member in provided code, did you mean selected? - Asperi
HI @Asperi, it was a typo in the code I copied here. I have updated the post. - Aнгел
Did you try .animation(self.selectedIdx == nil ?Animation.easeInOut.delay(0.1*Double(self.colors.count-idx)) : Animation.easeInOut.delay(0.1*Double(idx)))? - cbjeukendrup
hi @cbjeukendrup, it doesn't work. As soon as I use variable idx in both sides of the ternary operator, I get an error - If I use a constant number in one side of the ternary operator and idx in the other side, it works but I need to use idx on both sides. - Aнгел

2 Answers

0
votes

Not sure where is the problem, but the following test code works here. Tested with Xcode 11.2 / iOS 13.2.

demo

struct ContentView: View {
    @State private var selectedIdx: Int?
    var colors : [Color] = [.red, .orange, .yellow, .green, .blue]

    var body: some View {
        VStack {
            //some other views that change "selectedIdx" (the @State var)
            Button("Reset") { self.selectedIdx = nil }
            //...
            ForEach(0..<colors.count) { idx in
                self.row(index: idx)
                    //some other view modifiers that will be animated
                    .animation(Animation.easeInOut.delay(self.selectedIdx == nil ? 0.1*Double(self.colors.count - idx) : 0.1*Double(idx)))
                    .onTapGesture { self.selectedIdx = idx }
            }
        }
    }

    func row(index: Int) -> some View {
        Rectangle()
            .fill(self.selectedIdx == index ? self.colors[index] : Color.black)
            .frame(width: 70, height: 100)
    }
}
0
votes

Xcode 11.3.1 was buggy. Now that I updated to 11.4.1 it works fine.