Skip to content

Instantly share code, notes, and snippets.

@dr2050
Last active May 1, 2023 18:22
Show Gist options
  • Save dr2050/c839c309346903c9d4c4d30023aa5163 to your computer and use it in GitHub Desktop.
Save dr2050/c839c309346903c9d4c4d30023aa5163 to your computer and use it in GitHub Desktop.
TwoStateButton.swift
struct TwoStateButton<Content: View>: View {
@State private var isPressed = false
let touchDownView: () -> Content
let touchUpView: () -> Content
let action: () -> ()
let touchDownAction: (() -> ())?
var body: some View {
Button(action: action, label: {
ZStack {
if isPressed {
touchDownView()
} else {
touchUpView()
}
}
}).buttonStyle(CustomButtonStyle(onPressed: {
isPressed = true
touchDownAction?()
}, onReleased: {
isPressed = false
}))
}
// https://stackoverflow.com/a/71714195/8047
private struct CustomButtonStyle: ButtonStyle {
var onPressed: () -> Void
var onReleased: () -> Void
// Wrapper for isPressed where we can run custom logic via didSet (or willSet)
@State private var isPressedWrapper: Bool = false {
didSet {
// new value is pressed, old value is not pressed -> switching to pressed state
if (isPressedWrapper && !oldValue) {
onPressed()
}
// new value is not pressed, old value is pressed -> switching to unpressed state
else if (oldValue && !isPressedWrapper) {
onReleased()
}
}
}
// return the label unaltered, but add a hook to watch changes in configuration.isPressed
func makeBody(configuration: Self.Configuration) -> some View {
return configuration.label
.onChange(of: configuration.isPressed, perform: { newValue in isPressedWrapper = newValue })
}
}
}
@dr2050
Copy link
Author

dr2050 commented May 1, 2023

In the end, in most cases the ON state won't show fast enough anyway... sad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment