What's the best way to create a fully dynamic UIMenu for a UIButton or UIBarButtonItem?

I've got a UIBarButtonItem in my app that currently presents an action sheet of items. I want to switch this to a UIMenu with iOS 14's new APIs for buttons and bar button items. But somme of the contents of the action sheet change based on the state of the view controller when the action sheet is triggered.

With the action sheet, I generate a different action sheet every time the bar button item's target action is called. But with the new APIs, I have to generate the menu ahead of time and assign it to the button.

What's the best way to get the menu to update every time it's presented? I tried UIDeferredMenuElement, but it caches the result of its provider.

Feedback FB7824467 suggests adding a property to UIDeferredMenuElement to disable the caching of the provider result.

Accepted Reply

This is now solved with a new API in iOS 15.

https://developer.apple.com/documentation/uikit/uideferredmenuelement/3857602-elementwithuncachedprovider?language=objc

  • Would anyone be able to briefly describe how to use this? It is undocumented and there are only four or five web search results for elementWithUncachedProvider, none useful.

  • I see now that it is the same signature as init. Here is an example.

    let deferredMenuElement = UIDeferredMenuElement.uncached { completion in let action = UIAction(title: "Title", handler: { _ in }) completion([action]) }
Add a Comment

Replies

One approach: You can keep a reference to the UIBarButtonItem, regenerate the menu when the state changes and assign it to the bar button item menu property.

I was thinking you could keep a reference to the UIAction instead and modify the title or state properties, but UIMenu appears to cache these values, so the changes are not reflected in the menu.

Steve

This is now solved with a new API in iOS 15.

https://developer.apple.com/documentation/uikit/uideferredmenuelement/3857602-elementwithuncachedprovider?language=objc

  • Would anyone be able to briefly describe how to use this? It is undocumented and there are only four or five web search results for elementWithUncachedProvider, none useful.

  • I see now that it is the same signature as init. Here is an example.

    let deferredMenuElement = UIDeferredMenuElement.uncached { completion in let action = UIAction(title: "Title", handler: { _ in }) completion([action]) }
Add a Comment