I need to prevent UISwitch (or Toggle for SwiftUI) programmatical state change. I just want the state to change with user interaction.
The below code working on debug mode.
SwiftUIView
import SwiftUI
struct SwiftUIView: View {
@State var myState = false
@State var myProvider = MyProvider()
var body: some View {
Toggle("Let me in", isOn: $myState.onChange(myProvider.checkStateAction))
.textFieldStyle(.roundedBorder)
.padding(.trailing).padding(.leading)
}
}
}
@available(iOS 13.0, *)
extension Binding {
func onChange(_ handler: @escaping (Value) -> Void) -> Binding<Value>
{
Binding(
get: { self.wrappedValue },
set: { newValue in
self.wrappedValue = newValue
handler(newValue)
}
)
}
}
MyProvider
import Foundation
public final class MyProvider: NSObject {
public var onCheckBoxStateChanged: ((_ state: Bool) -> Void)?
private(set) var state: Bool = false
internal var stateChanger: Bool = false {
didSet {
state = self.stateChanger
}
}
public override init() {
super.init()
}
@objc public final func checkStateAction(to value: Bool) {
let symbols = Thread.callStackSymbols
let str: String = symbols[3]
if str.contains("sendAction") == false &&
str.contains("SwiftUI7Binding") == false {
print("It's done")
}
state.toggle()
onCheckBoxStateChanged?(state)
}
}
Please tell me how can I do that? Or you can show me another way :)
Thanks..
CodePudding user response:
What you can do is disable the Toggle's interaction and overlay it with a Button so that when the user presses on the Toggle, the button is tapped and you call whatever function you want:
struct SwiftUIView: View {
@State var myState = false
@State var myProvider = MyProvider()
var body: some View {
Toggle("Let me in", isOn: $myState)
.allowsHitTesting(false)
.textFieldStyle(.roundedBorder)
.padding(.trailing).padding(.leading)
.overlay {
Button(action: {
myProvider.checkStateAction()
}) {
Color.clear
}
}
}
}
CodePudding user response:
To disable UISwitch:
switch.isEnabled = false
To put UISwitch off:
switch.isOn = false
To put UISwitch on:
switch.isOn = true
To hide UISwitch:
switch.isHidden = true
CodePudding user response:
struct SwiftUIView: View {
@State var myState = false
var sourceOfTruthValue: Bool {
return sourceOfTruth.wrappedValue
}
private var sourceOfTruth: Binding<Bool> {
var value = false
return Binding {
return value
} set: { newValue in
value = newValue
myState = newValue
}
}
var body: some View {
Toggle("toggle1", isOn: sourceOfTruth)
.textFieldStyle(.roundedBorder)
.padding(.trailing).padding(.leading)
Toggle("toggle2", isOn: $myState)
}
}
Added 2 toggles to experiment with. When toggle1 is changed only then sourceOfTruth is updated. When toggle2 is updated, sourceOfTruth is not updated.
Changing myState won't update the sourceOfTruth.
You can always read the value of sourceOfTruth from sourceOfTruthValue.
You can run the above in a playground:
import PlaygroundSupport
import SwiftUI
struct ContentView: View {
var body: some View {
SwiftUIView()
}
}
PlaygroundPage.current.setLiveView(ContentView())
