1

Consider a UIVIewController where a custom back button needs to be set. The reason is that the user should be presented a confirmation dialog before navigating back where they can cancel the navigation, in case the back button was tapped accidentally. If the user confirms, a method in the UIVIewController should be executed.

The UIVIewController is wrapped in a UIViewControllerRepresentable. In a UIKit environment, the UIVIewController could just replace the back button like so:

let button = UIButton(type: .system)
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button)

However, since the view controller is presented in a SwiftUI NavigationView via a UIViewControllerRepresentable, I tried to set it for the parent view controller:

parent?.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button)

This doesn't work. In fact, it results in 2 back buttons, the original one to the left and the custom added one to the right:

enter image description here

Even if UIViewControllerRepresentable.navigationBarItems(leading:) is set instead, then a second button is added to to the original back button.

How can the UIVIewController set the custom back button?

Manuel
  • 14,274
  • 6
  • 57
  • 130

1 Answers1

0

In the presenting view, hide the UIViewControllerRepresentable's navigation bar back button. One would think that this only removes the back button, but if there is no other navigation item, the whole navigation bar is removed. To avoid this, also add an empty Text view:

MyViewControllerWrapper
   .navigationBarBackButtonHidden(true)
   .navigationBarItems(leading: Text(""))

This removes the NavigationView's back button, leaving only the custom added button. But now, the view controller cannot be dismissed programmatically anymore with:

navigationController?.popViewController(animated: true)

So in the UIViewControllerRepresentable the presentationMode is passed to the UIViewController:

@Environment(\.presentationMode) var presentationMode
...
viewController.presentationMode = presentationMode

Then in the UIViewController, when the back button is tapped, the view is dismissed with:

presentationMode?.wrappedValue.dismiss()

It works, but I'm sure there's a more elegant solution out there.

Manuel
  • 14,274
  • 6
  • 57
  • 130