iOS开发:如何将长按手势传递给UIContextMenu预览控制器
Hey there, I totally get how frustrating this must be—context menus and gesture recognizers can feel like they're fighting each other under the hood! Let's break down what's happening and walk through a solution that'll get your long press gesture working with the second view controller.
Why This Happens
When you present a preview view controller via UIContextMenuConfiguration, the system's built-in UILongPressGestureRecognizer takes over to manage the context menu interaction. This is why your first view controller's long press gets canceled—system gestures have higher priority by default. Additionally, the preview controller doesn't automatically forward gesture events because the system assumes it's just for quick previews, not interactive gestures.
Step-by-Step Solution
1. Update Your Second View Controller
We'll add a custom long press gesture recognizer to SecondViewController, configure it to play nice with system gestures, and handle the gesture events:
import UIKit class SecondViewController: UIViewController, UIGestureRecognizerDelegate { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // Set up custom long press gesture let customLongPress = UILongPressGestureRecognizer( target: self, action: #selector(handleCustomLongPress(_:)) ) customLongPress.delegate = self // Prevent the gesture from blocking touch events to other elements customLongPress.cancelsTouchesInView = false // Match system's default long press duration to sync with context menu trigger customLongPress.minimumPressDuration = 0.5 view.addGestureRecognizer(customLongPress) } @objc private func handleCustomLongPress(_ gesture: UILongPressGestureRecognizer) { switch gesture.state { case .began: print("Second VC: Long press started!") // Add your custom logic here (e.g., show additional actions) case .ended: print("Second VC: Long press ended!") // Clean up or finalize actions here default: break } } // Allow our custom gesture to work alongside system gestures func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { // Only allow simultaneous recognition with the system's collection view cell long press if otherGestureRecognizer is UILongPressGestureRecognizer, otherGestureRecognizer.view is UICollectionViewCell { return true } return false } }
2. Adjust Context Menu Configuration (Optional Tweak)
In your first view controller's contextMenuConfigurationForItemAt method, you don't need to change much, but you can ensure the preview is set up to allow interaction:
func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { let configuration = UIContextMenuConfiguration(identifier: indexPath as NSCopying) { () -> UIViewController? in let secondViewController = SecondViewController() // Enable user interaction on the preview (it's enabled by default, but explicit is safe) secondViewController.view.isUserInteractionEnabled = true return secondViewController } actionProvider: { (_) -> UIMenu? in return nil } return configuration }
Key Explanations
cancelsTouchesInView = false: Ensures our custom gesture doesn't block touch events from reaching other parts of the preview controller.- Simultaneous Gesture Recognition: The delegate method tells the system our custom gesture can run alongside the system's long press, so both the context menu preview and our gesture trigger as expected.
- Matching Duration: Setting
minimumPressDurationto 0.5s (the system default) syncs our gesture with when the context menu preview appears.
This setup should let your second view controller receive the long press gesture while the context menu preview is displayed, without the first controller's gesture getting canceled prematurely.
内容的提问来源于stack exchange,提问作者riccardo

