Search code examples
swiftlookupuimenucontrollertextkit

Swift `UIMenuController` custom action


I have implemented custom text view using TextKit. Also I have custom text selection implemented with UILongPressGesture. I've made progress in copying selected text with standard pop-up menu UIMenuController.

I want to implement custom text definition. Either overriding standard define action (have no clue if it's even exist) or with custom UIMenuItem.

So far, I have following:

@objc func longTap(sender: UILongPressGestureRecognizer) {
    ...
    becomeFirstResponder()
    let copyItem = UIMenuItem(title: "Copy", action: #selector(copySelector))
    let defineItem = UIMenuItem(title: "Define", action: #selector(defineSelector))
    UIMenuController.shared.menuItems = [copyItem, defineItem]
    UIMenuController.shared.setTargetRect(...)
    UIMenuController.shared.setMenuVisible(true, animated: true)
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if action == #selector(CenterViewController.copySelector) {
        return true
    } else if action == #selector(CenterViewController.defineSelector) {
        return true
    }
    return false
}

....

@objc func defineSelector() {
    // Use device's dictionary? 
    // ??
    customTextView.clearSelection()
}

And here's question: How to implement defineSelector?

I have searched everywhere, but there is no answers. Is there any way to use dictionaries and present modal view with definitions? As it is done by system with any selected text.


Solution

  • Never mind, I found a solution:

    @objc private func defineSelector() {
        if let text = textToCopy {
            let txt = UITextView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
            txt.isHidden = true
            view.addSubview(txt)
            txt.text = text
            txt.isEditable = false
            txt.becomeFirstResponder()
            txt.selectedRange = NSRange(0..<text.count)
            let selector = Selector(("_define:"))
            if txt.canPerformAction(selector, withSender: nil) {
                txt.perform(selector, with: nil)
            }
            txt.removeFromSuperview()
        }
        customTextView.clearSelection()
    }