1

I want to record the user's behavior on a UITextViewer. Specifically, I want to programmatically capture when the user tapped text menu functions such as copy, cut, translate, select all, look up.

This question (How can I detect that a user has tapped a formatting button in a UIMenuController?) seems to be the closest one, but I want to know the code for Swfit instead of Object-c.

How can I observe when the user tapped a specific text menu? I would also like to know which words were selected when a specific menu was called.

user8460166
  • 73
  • 1
  • 6
  • 24
  • [swift version](https://developer.apple.com/documentation/uikit/uiresponder/1621105-canperformaction) of the method. And [this](https://developer.apple.com/documentation/swift/using-objective-c-runtime-features-in-swift) for how to use selectors in swift – Ptit Xav Jul 16 '22 at 07:56
  • Thank you for your comment and links, @PtitXav. If I understand correctly, `canPerformAction` is used to disable (or enable) specific menus (e.g., https://stackoverflow.com/questions/72518059/how-to-disable-share-and-look-up-in-uitextview/72564761#72564761). Does this get called when each menu is used as well? If so, I am wondering how to distinguish when it is called for creating menus and for using menus. Could you provide an example code for that? – user8460166 Jul 16 '22 at 13:32

1 Answers1

1

Here some code to not have paste in menu when selected text contains a certain String ("XXX") :

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    let canPerformAction = super.canPerformAction(action, withSender: sender)
    
    // Next line can help you find menu action names
    print("canPerformAction:\(action):sender:\(String(describing: sender))=\(canPerformAction)")

    let pasteAction = NSSelectorFromString("paste:")
    
    if canPerformAction && action == pasteAction {
        // Set true/false based on your requirement
        // Check for current selected text
        let range = self.selectedRange
        guard let swiftRange = Range(range, in: self.text) else {return false}
        let selectedText = self.text[swiftRange]
        if selectedText.contains("XXX") {
            return false
            
        }
        return true
    }
    
    
    return canPerformAction
}

The action is computed each time the menu appears. So if you change selection, the check is again done and the paste command may be there or not. Hope this can help you,

Ptit Xav
  • 3,006
  • 2
  • 6
  • 15