— SwiftUI, Binding, Programming — 1 min read
SwiftUI is a powerful framework for building user interfaces across all Apple platforms. One of its key features is the data flow mechanism, which includes property wrappers like @State, @Binding, @EnvironmentObject, and more. In this article, we'll focus on @Binding and how it can be used to control sheet navigation.
@Binding is a property wrapper in SwiftUI that establishes a two-way connection between a property that stores data, and a view that displays and changes the data. It allows us to create a mutable state in one view and pass a reference to another view. This way, when the state changes in the second view, it also changes in the first view.
Let's consider the code below. This view is presented as a sheet and has a @Binding variable showPurchaseModal:
1import SwiftUI2
3struct OnboardingView: View {4 @Binding var showPurchaseModal: Bool5 6 var body: some View {7 VStack {8 Spacer()9 Text("Welcome to the App!")10 Spacer()11 Button {12 showPurchaseModal = true13 } label: {14 Text("Continue")15 }16 }17 .onDisappear {18 showPurchaseModal = true19 }20 }21}In this example, when the "Continue" button is pressed or the OnboardingView disappears, showPurchaseModal is set to true. This change is reflected in the parent view that owns the actual state.
Here's how the parent view might look:
1struct ContentView: View {2 @State private var showOnboarding = true3 @State private var showPurchaseModal = false4
5 var body: some View {6 VStack {7 Button {8 showOnboarding = true9 } label: {10 Text("Show Onboarding")11 }12 }13 .sheet(isPresented: $showOnboarding) {14 OnboardingView(showPurchaseModal: $showPurchaseModal)15 }16 .sheet(isPresented: $showPurchaseModal) {17 Text("Purchase Modal")18 }19 }20}In ContentView, showOnboarding and showPurchaseModal are @State variables. When showPurchaseModal changes in OnboardingView, it also changes in ContentView due to the @Binding. This triggers a re-render of ContentView, presenting the "Purchase Modal" sheet - after OnboardingView has disappeared(it doesn't matter if the user dismissed with a button or uses the gesture to hide the sheet).
If you aren't using the new NavigationStack for routing in your app it's kind of difficult to replace one screen with another screen(if your app is still relying just on NavigationLink for example). I personally wanted to show an onboarding screen and then show the user a different screen after that but also dismiss the onboarding screen. I already had the screen that I wanted to show wired up as a sheet in the previous screen. I did do some experimenting with trying to use dismiss but couldn't quite get the functionality I wanted and that's why I settled on the above solution and just past a @Binding that could be triggered in OnboardingView instead.