Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS13 Context Menu How to show or navigate to the current peeking view when tapping on it

I'm trying to implement "Context Menu" in iOS13 in a table view (tried collection view as well, they have same issue):

I followed the instruction here , created a collection view with bunch of photos, and when 3d touch, I will get a preview with an action list, like this:

Peek and Menu View

Collection View

The delegate method in UITableView:

- (void)tableView:(UITableView *)tableView willCommitMenuWithAnimator:
(id<UIContextMenuInteractionCommitAnimating>)animator;

and in collectionView

- (void)collectionView:(UICollectionView *)collectionView willCommitMenuWithAnimator:
(id<UIContextMenuInteractionCommitAnimating>)animator;

both don't have "indexPath";

So there is no way for me to pass in the current cell or index I'm peeking.

I want to implement this delegate method so when I tap on the preview image, it will navigate to the expected page with information that's bounded to the current cell.

What I want and tried is something like this:

func collectionView(_ collectionView: UICollectionView, willCommitMenuWithAnimator animator: UIContextMenuInteractionCommitAnimating) {
    animator.addAnimations {
        self.show(PreviewViewController(image: UIImage(named: "indexpathString")), sender: self)
    }
}

and the indexpathString is related to the current selected cell or collection so I can init the viewController based on it.

Please let me know if there is any other way to do this.

like image 995
RobotX Avatar asked Aug 01 '19 01:08

RobotX


People also ask

How do I display context menu?

The context menu (right-hand mouse button or SHIFT+F10 ) allows you to display a context-sensitive menu. The context is defined by the position of the mouse pointer when the user requests the menu. A context menu allows the user to choose functions that are relevant to the current context.

Where is the context menu on Iphone?

You access contextual menus using a touch and hold gesture or 3D Touch if you have it. This makes it available on all devices running iOS 13 or later. The contextual menu presents a menu of actions and a preview of the affected item. You can create submenus though Apple recommends limiting them to one level.

What is context menu in iOS?

In iOS and iPadOS, a context menu can display a preview of the current content near the list of commands. People can choose a command in the menu or — in some cases — they can tap the preview to open it or drag it to another area. Prefer a graphical preview that clarifies the target of a context menu's commands.

How do you show a menu when a button is pressed Swift?

As of iOS 14 and SwiftUI 2 we can now add a pop out menu to any button in our app. We can implement this by using the new Menu keyword. Menus in some way are going to replace the current action sheets used in iOS apps. The problem with action sheets is they only show up at the bottom of our screen.


2 Answers

There's a property in the animator called previewViewController that is of type UIViewController?. This is the same as the previewProvider you set in tableView(_:contextMenuConfigurationForRowAt:point:), so if you set the previewProvider as your destination view controller, you can do something like this:

Set your previewProvider

override func tableView(
    _ tableView: UITableView,
    contextMenuConfigurationForRowAt indexPath: IndexPath,
    point: CGPoint
) -> UIContextMenuConfiguration? {
    return UIContextMenuConfiguration(
        identifier: nil,
        previewProvider: { () -> UIViewController? in
            let string = yourDataSource[indexPath.row]
            return PreviewViewController(image: UIImage(named: string))
        }
    )
    // actionProvider has a default value of nil, so you can omit it
}

Use the animator to show it

override func tableView(
    _ tableView: UITableView, 
    willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, 
    animator: UIContextMenuInteractionCommitAnimating
) {
    guard let destinationViewController = animator.previewViewController else {
        return
    }

    animator.addAnimations {
        self.show(destinationViewController, sender: self)
    }
}
like image 82
alobaili Avatar answered Sep 17 '22 13:09

alobaili


The function contextMenuInteraction(_:willCommitWithAnimator:) has been superseded by tableView(_:willPerformPreviewActionForMenuWith:animator:), which provides the UIContextMenuConfiguration associated with the presented menu. At the point where your menu is presented, assign an identifier which will allow you to identify the row. The identifier should be any NSCopying object - e.g. an NSIndexPath:

override func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
    // Pass the indexPath as the identifier for the menu configuration
    return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: nil) { _ in
        // Empty menu for demonstration purposes
        return UIMenu(title: "", children: [])
    }
}

and then use that identifier in the willPerformPreviewActionForMenuWith:animator: function:

override func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
    guard let indexPath = configuration.identifier as? IndexPath else { return }

    // Use your index path to get your destination VC in some way; arbitrary example shown...
    let destinationVc = destinationViewController(for: indexPath)

    // Then animate the appearance of the VC with the provided animator
    animator.addAnimations {
        self.show(destinationVc, sender: self)
    }
}
like image 39
Andrew Bennet Avatar answered Sep 20 '22 13:09

Andrew Bennet