Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a binding from an environment value in SwiftUI

Tags:

swiftui

I have an environment value as follows:

@Environment(\.isPresented) var isPresented: Bool

This environment value is defined as such:

private struct IsPresented: EnvironmentKey {
    static let defaultValue: Bool = false
}

extension EnvironmentValues {
    var isPresented: Bool {
        get { self[IsPresented.self] }
        set { self[IsPresented.self] = newValue }
    }
}

extension View {
    func isPresented(_ isPresented: Bool) -> some View {
        environment(\.isPresented, isPresented)
    }
}

I want to read this environment value in one of my views to decide whether or not to show a view as a full screen. However, this line of code doesn't work:

.fullScreenCover(isPresented: self.$isPresented) {
// It says there's no such member in my view.

Thus, my question is, how can I convert my environment value to a binding, since .fullScreenCover expects a binding?

like image 320
thecanteen Avatar asked Oct 21 '25 04:10

thecanteen


2 Answers

If you want it to be a writable value, I think your Environment value should be Binding<Bool> instead of just Bool. This is how the system's presentationMode works, for example.

private struct IsPresented: EnvironmentKey {
    static let defaultValue: Binding<Bool> = .constant(false)
}

extension EnvironmentValues {
    var isPresented: Binding<Bool> {
        get { self[IsPresented.self] }
        set { self[IsPresented.self] = newValue }
    }
}

extension View {
    func isPresented(_ isPresented: Binding<Bool>) -> some View {
        environment(\.isPresented, isPresented)
    }
}

struct ContentView : View {
    @State private var isPresented = false
    
    var body: some View {
        ChildView().environment(\.isPresented, $isPresented)
    }
}

struct ChildView : View {
    @Environment(\.isPresented) var isPresented: Binding<Bool>
    
    var body: some View {
        Button("Test") {
            isPresented.wrappedValue = true
        }
        .fullScreenCover(isPresented: isPresented) {
            Text("Sheet")
        }
    }
}
like image 152
jnpdx Avatar answered Oct 22 '25 23:10

jnpdx


If you really want @Environment(\.isPresented) var isPresented: Bool as Bool, then you can create Binding in place, like

.fullScreenCover(isPresented: Binding(
    get: { isPresented },
    set: { isPresented = $0 }
 )) {
like image 28
Asperi Avatar answered Oct 22 '25 22:10

Asperi