Context Menu Problems

I'm unable to find any sample code for the new iOS13 context menus features or UICommand features. I'm curious about how to make all this stuff work together correctly.


Im within UITableView's `contextMenuConfigurationForRowAt` method, and trying to return a UIContextMenuConfiguration with a `UIContextMenuActionProvider


I've tried the following that was taken from a WWDC slide @ 44:33 Modernizing your app for iOS 13.

        let actionProvider: UIContextMenuActionProvider = { suggestedActions in
            return UIMenu(children: [UIAction(title: "Open in new Window"){ action in },
                                     UIAction(title: "Delete", options:.destructive){ action in}])
        }
        
        let config = UIContextMenuConfiguration(identifier: "SO.UNIQUE" as NSCopying, previewProvider: nil, actionProvider: actionProvider)
        return config
    }

This says that UIMenu doesnt support being init'd with children elements, and only has init(coder:) available.
Is this stuff ready for adoption this beta? There's no mention in the release notes.

Replies

The set of APIs used in the WWDC talks were not included in iOS 13 Beta 1.


The following article details what's possible now:

https://kylebashour.com/posts/ios-13-context-menus

There is a great article with explanations: https://kylebashour.com/posts/ios-13-context-menus


Unfortunately the API implementation is still incomplete in iOS 13 developer beta 3.

Does it work with Beta 4 now? Or does it still not work within a UITableView?

The API still seems to be unfinished and I can't see any changes in beta 5. For example, UIContextMenuInteractionCommitAnimating has a preferredCommitStyle with .dismiss and .pop choices, but they're undocumented. I want a pre-iOS 13 3D Touch "Pop" like commit animation so the new view controller just pops into place without the preview having to animate away.


Performing a push on the navigation stack alongside the dismiss animation results in the preview animating back to a moving target (the view controller sliding off to the left of the navigation controller). That even animates off the left of a form sheet on iPad, above the VC that presented the form sheet (it's hard to explain, but you'll know if you see it!)


It doesn't seem to be possible to *present* a new VC alongside the animation (I think the context menu is a presentation and you can't present twice), so you have to use addCompletion on the animator to present after the preview has animated all the way back. That's pretty slow as you have to wait for the dismissal spring animation to complete.


Safari seems to be able to just instantly show a new VC when tapping on the preview (no animating away of the preview - the new web page just appears). I don't know how they're doing it! That preferredCommitStyle sounds like it is designed for that but it's not working for me (at least not in table views, which abstracts the API slightly).

ios 13 beta 6 seems to be a step backwards with regards to context menus. Maybe there's some API changes and we need Xcode 11 beta 6. Running an app on a real device running iOS 13 beta 6 using an Xcode 11 beta 5-built app throws an exception when I try and show a context menu:


[<_UIPreviewPlatterView 0x104899010> valueForUndefinedKey:]: this class is not key value coding-compliant for the key expandedContentWrapperView.

(null)


I can contuinue in the debugger (or disable the exception breakpoint I usually have configured), so that's not a complete show stopper.


However, where I use my own UIContextMenuInteraction on a view the contextMenuInteraction:willCommitWithAnimator: (Obj-C) delegate method doesn't seem to be called when tapping the preview to commit it. The preview is also not dismissed.


Where I use a table view and its wrapper delegate methods, I see the same exception, but I *can* tap the preview to dismiss it. However, tableView:willCommitWithAnimator: is not called.


Here's hoping Xcode 11 beta 6 comes soon and we can look at the headers for clues about what has changed.

Hello,


Same issue, tableView:willCommitWithAnimator: is not called anymore....

Same here...but Apple's Mail / Messages app seems to allow tapping on the preview.

Yes, Apple's own apps (Photos, Mail) do still seem to allow the preview to commit. My guess is that the name of the method has changed (perhaps to pass an indexPath?) but because they didn't release a new Xcode beta, we can't see the headers.


Interestingly/worryingly, there's still no "pop" style commit which the old 3D Touch Peek & Pop interaction had. In the Photos app if you preview a photo and tap on it, the preview animates back to the collection view and then, BLAM, the photo detail appears full screen without animation. It looks awful!

As I suspected, the API for committing previews has changed slightly. I've not had a chance yet to change my code, but for the benefit of people following this issue, the differences can be seen in the wonderful codeworkshop web site: http://codeworkshop.net/objc-diff/sdkdiffs/ios/13.0b6/UIKit.html

I'm still waiting for a prevous comment to get past moderation because it had an external link. Here's what I've found so far (translate from Obj-C as necessary):


Old delegate method API:


- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willCommitWithAnimator:(id<UIContextMenuInteractionCommitAnimating>)animator API_AVAILABLE(ios(13.0))


New delegate method API:


- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willPerformPreviewActionForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration animator:(id<UIContextMenuInteractionCommitAnimating>)animator API_AVAILABLE(ios(13.0))



I.e. the method name has changed and the UIContextMenuConfiguration is now passed (hurrah!)


In my quick testing it looks like the "pop" animation now works! I can set the the dismiss style


animator.preferredCommitStyle = UIContextMenuInteractionCommitStylePop;


and add a competion block to present a new view controller (it's never been possible to present directly in the delegate method or in the animation block because the preview is an already presented view controller).