Skip to content

Instantly share code, notes, and snippets.

@magnuskahr
Last active December 11, 2021 18:55
Show Gist options
  • Save magnuskahr/2143ec7cc6b89e55dd39d4c42924d29e to your computer and use it in GitHub Desktop.
Save magnuskahr/2143ec7cc6b89e55dd39d4c42924d29e to your computer and use it in GitHub Desktop.
Need to show a button that is always visible and which action relies on a value, but disabled if the value is missing? Use UnwrappingButton for an easy solution.
import SwiftUI
struct UnwrappingButton<Label: View, T>: View {
enum Unwrapping<T> {
case element(value: T?, action: (T) -> Void)
case binding(value: Binding<T?>, action: (Binding<T>) -> Void)
var value: T? {
switch self {
case .element(let value, _):
return value
case .binding(let value, _):
return value.wrappedValue
}
}
func run() {
switch self {
case .element(let value, let action):
if let value = value {
action(value)
}
case .binding(let value, let action):
if let value = Binding(value) {
action(value)
}
}
}
}
let unwrapping: Unwrapping<T>
@ViewBuilder let label: Label
init(element: T?, action: @escaping (T) -> Void, @ViewBuilder label: () -> Label) {
self.unwrapping = .element(value: element, action: action)
self.label = label()
}
init(element: Binding<T?>, action: @escaping (Binding<T>) -> Void, @ViewBuilder label: () -> Label) {
self.unwrapping = .binding(value: element, action: action)
self.label = label()
}
var body: some View {
Button {
unwrapping.run()
} label: {
label
}
.disabled(unwrapping.value == nil)
}
}
extension UnwrappingButton where Label == Text {
init(element: T?, title: String, action: @escaping (T) -> Void) {
self.unwrapping = .element(value: element, action: action)
self.label = Text(title)
}
init(element: Binding<T?>, title: String, action: @escaping (Binding<T>) -> Void) {
self.unwrapping = .binding(value: element, action: action)
self.label = Text(title)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment