UIContextMenuInteraction

UIContextMenuInteraction

UIMenu vs UIContextMenuInteraction vs UIPointerInteraction
我正在尝试以与“文件或页面”应用程序相同的方式设置UIContextMenuInteraction:

  • (长按)在空白处的任意位置显示黑色水平UIMenu
  • 在空白区域中的任意位置单击鼠标指针(右键/控制),显示上下文菜单

  • 请参阅下面随附的GIF上的演示。

    我可以设置UIContextMenuInteraction,并在其UIContextMenuInteractionDelegate中返回包含我要显示的项目的UIContextMenuConfiguration

    对于小的黑色UIMenu一样,我可以使用UILongPressGestureRecognizer并使用UIMenuController.shared.showMenu显示菜单。

    但是,当长按视图时,我无法阻止UIContextMenuInteraction触发并显示UITargetedPreview,现在似乎已经有了通过UITouchType提供的信息来识别不同的UIContextMenuInteractionDelegate的方法。

    如果没有UIContextMenuInteraction,我也找不到如何以编程方式显示上下文菜单。有没有办法做到这一点?



    在Files.app中如何实现?

    ios - iPadOS:防止不使用指针时触发UIContextMenuInteraction-LMLPHP

    最佳答案

    无法以编程方式触发上下文菜单,但是通过一些简单的簿记操作,您可以防止在不需要时显示该菜单(例如,当响应者上的触摸处于 Activity 状态时)。

    要隐藏预览,只需在UIContextMenuConfiguration的初始化程序中从previewProvider返回nil即可。

    这是一个以视图控制器的视图为目标的完整实现:

    import UIKit
    
    class ViewController: UIViewController {
    
        var touchesInSession = false
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let interaction = UIContextMenuInteraction(delegate: self)
            view.addInteraction(interaction)
    
            let recognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressHandler))
            view.addGestureRecognizer(recognizer)
        }
    
        @objc func longPressHandler(recognizer: UILongPressGestureRecognizer) {
            guard recognizer.state == .began else { return }
            presentMenu(from: recognizer.location(in: view))
        }
    
        func presentMenu(from location: CGPoint) {
            view.becomeFirstResponder()
            let saveMenuItem = UIMenuItem(title: "New Folder", action: #selector(createFolder))
            let deleteMenuItem = UIMenuItem(title: "Get Info", action: #selector(getInfo))
            UIMenuController.shared.menuItems = [saveMenuItem, deleteMenuItem]
            UIMenuController.shared.showMenu(from: view, rect: .init(origin: location, size: .zero))
        }
    
        @objc func createFolder() {
            print("createFolder")
        }
    
        @objc func getInfo() {
            print("getInfo")
        }
    
        // MARK: UIResponder
        override var canBecomeFirstResponder: Bool { true }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesBegan(touches, with: event)
            touchesInSession = true
        }
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesEnded(touches, with: event)
            touchesInSession = false
        }
    
        override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesCancelled(touches, with: event)
            touchesInSession = false
        }
    }
    
    extension ViewController: UIContextMenuInteractionDelegate {
        func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
            guard !touchesInSession else { return nil }
            let configuration = UIContextMenuConfiguration(identifier: "PointOnlyContextMenu" as NSCopying, previewProvider: { nil }, actionProvider: { suggestedActions in
                let newFolder = UIAction(title: "New Folder", image: UIImage(systemName: "folder.badge.plus")) { [weak self] _ in
                    self?.createFolder()
                }
                let info = UIAction(title: "Get Info", image: UIImage(systemName: "info.circle")) { [weak self] _ in
                    self?.getInfo()
                }
                return UIMenu(title: "", children: [newFolder, info])
            })
            return configuration
        }
    }
    
    

    07-24 09:27