Preventing toggle switch on and showing alert in Swiftui

Viewed 880

I have some Toggle Switches in a row but I want to prevent switches ON if already two of them is ON. And showing an Alert that maximum 2 of them is allowed to ON. Here is my code:

struct PreventToggle: View {

    @State private var isCheckeds = [false, true, true, false, false, false]
    @State var showAlert = false

    var body: some View {

        let numberOfTrue = isCheckeds.filter{$0}.count
        showAlert = numberOfTrue > 2

        return ForEach(0 ..< isCheckeds.count) { id in

                Toggle("Switch \(id)", isOn: self.$isCheckeds[id])
                    .alert(isPresented: self.$showAlert) {
                        Alert(title: Text("Maximum Limit!"), message: Text("Maximum limit is: 3"), dismissButton: .default(Text("Got it")))
                }
        }
    }
}

enter image description here

2 Answers

This is how it can work:

struct PreventToggle: View {
  @State private var isCheckeds = [false, true, true, false, false, false]
  @State var lastSelected = -1

  func alertBinding() -> Binding<Bool> {
    Binding<Bool>(
      get: {
        let numberOfTrue = self.isCheckeds.filter{$0}.count
        return numberOfTrue > 2 && self.lastSelected != -1
      },
      set: { _ in }
    )
  }

  func toggleBinding(for index: Int) -> Binding<Bool> {
    Binding<Bool>(
      get: {
        return self.isCheckeds[index]
      },
      set: { bool in
        self.isCheckeds[index] = bool
        self.lastSelected = index
      }
    )
  }

  var body: some View {
    VStack {
      ForEach(0 ..< isCheckeds.count) { id in
        Toggle("Switch \(id)", isOn: self.toggleBinding(for: id))
      }
    }
    .alert(isPresented: alertBinding()) {
      Alert(title: Text("Maximum Limit!"),
            message: Text("Maximum limit is: 3"),
            dismissButton: .default(Text("Got it"), action: {
              self.isCheckeds[self.lastSelected] = false
              self.lastSelected = -1
            })
      )
    }
  }
}

try this:

...but then the message never disappears, because you never set the toggle values back to 2...so this is what you still have to do. and maybe you should do your check inside the toggle action and not when building the view.

struct ContentView: View {

    @State private var isCheckeds = [false, true, true, false, false, false]
    @State var showAlert = false

    var body: some View {

        let numberOfTrue = isCheckeds.filter{$0}.count
        OperationQueue.main.addOperation {
            self.showAlert = numberOfTrue > 2
        }

        return VStack {
            ForEach(0 ..< isCheckeds.count) { id in

                Toggle("Switch \(id)", isOn: self.$isCheckeds[id])
                    .alert(isPresented: self.$showAlert) {
                        Alert(title: Text("Maximum Limit!"), message: Text("Maximum limit is: 3"), dismissButton: .default(Text("Got it")))
                }
            }
        }
    }
}
Related