'SwiftUI, Dismiss modal/page from child view

I am new to Swift/SwiftUI and want to know how to dismiss modal/page from nested child view.

Firstly, I am calling from Flutter, UIHostingController, then SwiftUI page. (currently showing as modal...)
After Navigating to SwiftUI, I am not able to use @environment data from child view.

Is there any ways for this to work? thanks in advance.

AppDelegate.swift

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller : FlutterViewController = self.window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel.init(name: "com.example.show", binaryMessenger: controller.binaryMessenger)
        channel.setMethodCallHandler({
            (call, result) -> Void in
            if call.method == "sample" {
                let vc = UIHostingController(rootView: ContentView())
                vc.modalPresentationStyle = .fullScreen
                controller.present(vc, animated: true,completion: nil)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ContentView.swift

struct ContentView: View{
    @Environment(\.presentationMode) var presentation: Binding<PresentationMode>
    private var childView: ChildView()

    var body: some View{
        NavigationView{
            ZStack{
                childView
                Button(action: {
// This works ************************
                    self.presentation.wrappedValue.dismiss()
                }, label: {
                    Text("close")
                })
            }
        }
    }
}

ChildView.swift

struct ChildView: View{
    @Environment(\.presentationMode) var presentation: Binding<PresentationMode>

    var body: some View{
        Button(action: {
// This won't do anything *********************************
            self.presentation.wrappedValue.dismiss()
// nor this↓ **********************************************
            if #available(iOS 15.0, *) {
               @Environment(\.dismiss) var dismiss;
                dismiss()
                dismiss.callAsFunction()
            }
            }, label: {
                Text("close")
            })
    }
}


Solution 1:[1]

I figured it out that NavigationView in ContentView.swift caused this issue.
Removing NavigationView, I could dismiss modal page from child view...
But this is not what I intended for :(...

    var body: some View{
//        NavigationView{    <--------
            ZStack{
                childView
                Button(action: {
                    self.presentation.wrappedValue.dismiss()
                }, label: {
                    Text("close")
                })
            }
//        }
    }

Solution 2:[2]

Since you had another NavigationView is your ContentView, the @Environment(\.presentation) inside ChildView is of a child and not the parent. Basically those two are from completely different Navigation stacks.

In order to still keep NavigationView inside your parent ContentView, you need to pass the presentation value from constructor of ChildView instead of environment:

ContentView.swift

struct ContentView: View{
    @Environment(\.presentationMode) var presentation: Binding<PresentationMode>

    var body: some View{
        NavigationView{
            ZStack{
                ChildView(parentPresentation: presentation)
                Button(action: {
                    self.presentation.wrappedValue.dismiss()
                }, label: {
                    Text("close")
                })
            }
        }
    }
}

In child view, use normal property instead of @Environment

ChildView.swift

struct ChildView: View{
    let parentPresentation: Binding<PresentationMode>

    var body: some View{
        Button(action: {
            self.parentPresentation.wrappedValue.dismiss()
            if #available(iOS 15.0, *) {
                @Environment(\.dismiss) var dismiss;
                dismiss()
                dismiss.callAsFunction()
            }
        }, label: {
            Text("Close")
        })
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Bhimsen Padalkar