Last active
February 23, 2023 16:50
-
-
Save yannxou/18ead574db14cab93f04212d8310ebee to your computer and use it in GitHub Desktop.
SwiftUI: Synchronize bindings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
extension View { | |
/// Synchronizes the bindings so changes in any of them are propagated to the other. | |
/// | |
/// The following example shows how to synchronize a Published property in a view model with a Binding used for presenting a sheet: | |
/// ``` | |
/// class ViewModel: ObservableObject { | |
/// @Published var isPresented = false | |
/// } | |
/// | |
/// struct ContentView: View { | |
/// @ObservedObject var viewModel: ViewModel | |
/// @State private var isPresented = false | |
/// | |
/// var body: some View { | |
/// Button { | |
/// viewModel.isPresented.toggle() | |
/// } label: { | |
/// Text("Show detail") | |
/// } | |
/// .sheet(isPresented: $isPresented) { | |
/// DetailView() | |
/// } | |
/// .sync($viewModel.isPresented, with: $isPresented) | |
/// } | |
/// } | |
/// | |
/// struct DetailView: View { | |
/// @Environment(\.dismiss) private var dismiss | |
/// | |
/// var body: some View { | |
/// Button { | |
/// dismiss() | |
/// } label: { | |
/// Text("Dismiss") | |
/// } | |
/// } | |
/// } | |
/// ``` | |
/// - Parameters: | |
/// - binding1: First binding | |
/// - binding2: Second binding | |
/// - Returns: A view that automatically syncs the two values. | |
func sync<T: Equatable>(_ binding1: Binding<T>, with binding2: Binding<T>) -> some View { | |
self | |
.onChange(of: binding1.wrappedValue) { | |
binding2.wrappedValue = $0 | |
} | |
.onChange(of: binding2.wrappedValue) { | |
binding1.wrappedValue = $0 | |
} | |
} | |
/// Synchronizes a binding with a @FocusState property wrapper so changes in any of them are propagated to the other. | |
/// | |
/// The following example shows how to synchronize a Published property in a view model with a view's FocusState property: | |
/// ``` | |
/// class ViewModel: ObservableObject { | |
/// @Published var hasFocus: Bool = false | |
/// } | |
/// | |
/// struct ContentView: View { | |
/// @ObservedObject private var viewModel = ViewModel() | |
/// @FocusState private var hasFocus: Bool | |
/// | |
/// var body: some View { | |
/// Form { | |
/// TextField("Text", text: $viewModel.textField) | |
/// .focused($hasFocus) | |
/// } | |
/// .sync($viewModel.hasFocus, with: _hasFocus) | |
/// } | |
/// } | |
/// ``` | |
/// - Parameters: | |
/// - binding: A binding | |
/// - focusState: A `@FocusState` property wrapper | |
/// - Returns: A view that automatically syncs the two values. | |
func sync<T: Equatable>(_ binding: Binding<T>, with focusState: FocusState<T>) -> some View { | |
self | |
.onChange(of: binding.wrappedValue) { | |
focusState.wrappedValue = $0 | |
} | |
.onChange(of: focusState.wrappedValue) { | |
binding.wrappedValue = $0 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment