DismissAction is not working properly.

To apply custom transition animations, I implemented a UIViewControllerRepresentable wrapping UINavigationController instead of using NavigationStack. The navigation stack pops correctly with DismissAction. However, when I call DismissAction after presenting my CustomNavigationStack with fullScreenCover(isPresented:onDismiss:content:), it doesn't work. I suspect that the DismissAction implementation does not handle this case. Is there a workaround for this?

Below is a simple reproduction code:

struct ChildView: View {
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        Button {
            dismiss()
        } label: {
            Text(verbatim: "Dismiss!!")
                .background(Color.yellow)
        }
    }
}

struct CustomSimpleVC: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIHostingController<ChildView> {
        let vc = UIHostingController(rootView: ChildView())
        vc.view.backgroundColor = .green
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIHostingController<ChildView>, context: Context) {}
}

struct CustomContainerVC: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
        let childVC = UIHostingController(rootView: ChildView())
        childVC.view.backgroundColor = .blue
        
        let vc = UIViewController()
        vc.addChild(childVC)
        vc.view.addSubview(childVC.view)
        childVC.view.frame = vc.view.bounds
        childVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        childVC.didMove(toParent: vc)
        return vc
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

struct CustomNavigationVC: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UINavigationController {
        let childVC = UIHostingController(rootView: ChildView())
        childVC.view.backgroundColor = .red
        
        let childVC2 = UIHostingController(rootView: ChildView())
        childVC2.view.backgroundColor = .gray
        
        let navVC = UINavigationController()
        navVC.viewControllers = [childVC, childVC2]
        return navVC
    }
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
}

struct ContentView: View {
    @State private var isNextPresented: Bool = false
    
    var body: some View {
        VStack {
            Button {
                isNextPresented = true
            } label: {
                Text(verbatim: "present")
            }
        }
        .fullScreenCover(isPresented: $isNextPresented, content: {
            VStack {
                CustomSimpleVC() // Works
                CustomContainerVC() // Works
                CustomNavigationVC() // Does not work
            }
        })
    }
}

#Preview {
    ContentView()
}
Answered by DTS Engineer in 795448022

You need a way to communicate the dismissal action from within the SwiftUI view to the UIKit NavigationController by passing down the isNextPresented binding down to the child views.

struct ChildView: View {
    @Binding var isPresented: Bool

    var body: some View {
        Button {
            isPresented = false
        } label: {
            Text("Dismiss!!")
                .background(Color.yellow)
        }
    }
}

struct ContentView: View {
    @State private var isNextPresented: Bool = false
    
    var body: some View {
        VStack {
            Button {
                isNextPresented = true
            } label: {
                Text(verbatim: "present")
            }
        }
        .fullScreenCover(isPresented: $isNextPresented, content: {
            VStack {
                ...
                CustomNavigationVC(isPresented: $isNextPresented)
            }
        })
    }
}

struct CustomNavigationVC: UIViewControllerRepresentable {
    @Binding var isPresented: Bool

    func makeUIViewController(context: Context) -> UINavigationController {
        let childVC = UIHostingController(rootView: ChildView(isPresented: $isPresented))
        childVC.view.backgroundColor = .red
        
        let childVC2 = UIHostingController(rootView: ChildView(isPresented: $isPresented))
        childVC2.view.backgroundColor = .gray
        
        let navVC = UINavigationController()
        navVC.viewControllers = [childVC, childVC2]
        return navVC
    }
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
}

You need a way to communicate the dismissal action from within the SwiftUI view to the UIKit NavigationController by passing down the isNextPresented binding down to the child views.

struct ChildView: View {
    @Binding var isPresented: Bool

    var body: some View {
        Button {
            isPresented = false
        } label: {
            Text("Dismiss!!")
                .background(Color.yellow)
        }
    }
}

struct ContentView: View {
    @State private var isNextPresented: Bool = false
    
    var body: some View {
        VStack {
            Button {
                isNextPresented = true
            } label: {
                Text(verbatim: "present")
            }
        }
        .fullScreenCover(isPresented: $isNextPresented, content: {
            VStack {
                ...
                CustomNavigationVC(isPresented: $isNextPresented)
            }
        })
    }
}

struct CustomNavigationVC: UIViewControllerRepresentable {
    @Binding var isPresented: Bool

    func makeUIViewController(context: Context) -> UINavigationController {
        let childVC = UIHostingController(rootView: ChildView(isPresented: $isPresented))
        childVC.view.backgroundColor = .red
        
        let childVC2 = UIHostingController(rootView: ChildView(isPresented: $isPresented))
        childVC2.view.backgroundColor = .gray
        
        let navVC = UINavigationController()
        navVC.viewControllers = [childVC, childVC2]
        return navVC
    }
    
    func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
}
DismissAction is not working properly.
 
 
Q