Get the title view of an editor style UINavigationItem (iOS 16+)

I'd like to match the behaviour of the new Freeform app by offering an Export as PDF function accessible from the title menu.

I can't figure out how to get the actual view that displays the document menu to supply as the UIActivityViewController's popoverPresentationController source view.

The Freeform app shows the PDF document sharing popover directly under the little arrow to the right of the document title, so there must be a way.

Answered by Frameworks Engineer in 740789022

As of iOS 16, UIMenuElement has a presentationSourceItem property for this exact purpose. When a UIAction or UICommand is added to this menu, its presentationSourceItem is the title view's arrow. You should be able to just do the following when using the default export command:

override func export(_ sender: Any?) {
    let vc = /* your view controller */
    
    if let command = sender as? UICommand {
        vc.modalPresentationStyle = .popover
        vc.popoverPresentationController?.sourceItem = command.presentationSourceItem
    }
    
    present(vc, animated: true)
}

or something like this if you're using a custom UIAction:

UIAction(title: "Export as PDF", image: UIImage(systemName: "doc.text")) { action in    
    let vc = /* your view controller */
    vc.modalPresentationStyle = .popover
    vc.popoverPresentationController?.sourceItem = action.presentationSourceItem
    
    present(vc, animated: true)
}

This explains how to add a menu, not popover, to a NavigationItem.

https://stackoverflow.com/questions/63299837/show-uimenu-when-single-tapping-uibarbuttonitem

Hope that will show you a way.

I'm already displaying the standard menu from the document name title view in my editor document-based iPad app.

The problem is how to display the popover connected to it, when the user chooses "Export" from this existing menu?

Accepted Answer

As of iOS 16, UIMenuElement has a presentationSourceItem property for this exact purpose. When a UIAction or UICommand is added to this menu, its presentationSourceItem is the title view's arrow. You should be able to just do the following when using the default export command:

override func export(_ sender: Any?) {
    let vc = /* your view controller */
    
    if let command = sender as? UICommand {
        vc.modalPresentationStyle = .popover
        vc.popoverPresentationController?.sourceItem = command.presentationSourceItem
    }
    
    present(vc, animated: true)
}

or something like this if you're using a custom UIAction:

UIAction(title: "Export as PDF", image: UIImage(systemName: "doc.text")) { action in    
    let vc = /* your view controller */
    vc.modalPresentationStyle = .popover
    vc.popoverPresentationController?.sourceItem = action.presentationSourceItem
    
    present(vc, animated: true)
}
Get the title view of an editor style UINavigationItem (iOS 16+)
 
 
Q