Search code examples
swiftuitoggleswiftui-navigationlink

SwiftUI: NavigationLinks dependent on Toggle states


I am trying to create a NavigationLink destination that changes if any one of several toggle switches are set to TRUE. I have worked out the if/then logic for the links using tags and a state variable. That is, if I manually set toggleCount = the links work correctly.

What I would like to do however, is set toggleCount = Number of True Switches. You can see my failed attempt to loop through the array and increment toggleCount. It fails because it does not conform to View.

Any advice on a clean way to implement this? I don't necessarily need to count the number of true switches, I just need to know if any one of them were set to true.

import SwiftUI

struct ToggleStruct : Identifiable {
    var id : Int
    var name : String
    var position : Bool
    
}

struct ContentView: View {
    
    @State var toggleArray = [ToggleStruct(id: 1, name: "Toggle 1", position: false),
                              ToggleStruct(id: 2, name: "Toggle 2", position: false),
                              ToggleStruct(id: 3, name: "Toggle 3", position: false)
    ]
    
    @State private var selection: Int? = nil
    
    var toggleCount = 0
    
    var body: some View {
        NavigationView {
            VStack {
                Text("Toggle Count: \(toggleCount)")
                
                ForEach(0..<toggleArray.count) { i in
                    Toggle(isOn: $toggleArray[i].position, label: {
                        Text(toggleArray[i].name)
                    })
                }
                
                NavigationLink(
                    destination: Text("Destination A"),
                    tag: 1,
                    selection: $selection,
                    label: {EmptyView()})
                
                NavigationLink(
                    destination: Text("Destination B"),
                    tag: 2,
                    selection: $selection,
                    label: {EmptyView()})
                
                Button(action: {
                    
                    //                ForEach(0..<toggleArray.count) { x in
                    //                    if toggleArray[x].position {
                    //                        toggleCount += 1
                    //                    }
                    //                }
                    
                    if toggleCount > 0 {
                        
                        selection = 1
                        
                    } else {
                        
                        selection = 2
                        
                    }
                    
                }, label: {
                    Text("Continue")
                })
                
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Solution

  • Would something like this work for you? You could change the logic in destinationView to be whatever you needed.

    import SwiftUI
    
    struct ContentView: View {
        @State var toggleOneIsOn = false
        @State var toggleTwoIsOn = false
        @State var toggleThreeIsOn = false
        
        var body: some View {
            NavigationView {
                Form {
                    Toggle("Toggle One", isOn: $toggleOneIsOn)
                    Toggle("Toggle Two", isOn: $toggleTwoIsOn)
                    Toggle("Toggle Three", isOn: $toggleThreeIsOn)
                    NavigationLink("Foo", destination: destinationView)
                }
            }
        }
        
        var destinationView: some View {
            switch (toggleOneIsOn, toggleTwoIsOn, toggleThreeIsOn) {
            case _ where toggleOneIsOn || toggleTwoIsOn || toggleThreeIsOn:
                return Text("At least one toggle is on")
            default:
                return Text("All toggles are off")
            }
        }
    }