Search code examples
iosnsattributedstringuimenucontrolleruimenuitem

UIMenuController doesn't update menu for first time


I have UITextView on which I want to add highlight as custom menu item. I have registered to following notification UIMenuControllerWillShowMenuNotification.

The method for the notification is something like this:

if textIsHighlighted {
    let highlightMenuItem = UIMenuItem(title: "Highlight", action: Selector("highlightText"))
    UIMenuController.sharedMenuController().menuItems = [highlightMenuItem]
}
else {
    let highlightMenuItem = UIMenuItem(title: "Dehighlight", action: Selector("highlightText"))
    UIMenuController.sharedMenuController().menuItems = [highlightMenuItem]
}

Although the first time the menucontroller fails to update even though it executes the part of code. It shows the last value. Where should I write this part of code as I feel that during willShow menuController it's already created and thus fails to update.


Solution

  • Hopefully you've solved this by now, but I've just figured this one out myself: Other answers have said you can update the menu items by adding it when the UIMenuControllerWillShowMenuNotification is called, but this wasn't working for me (iOS 9, Swift 2).

    Instead I implemented the UITextView delegate method: textViewDidChangeSelection and set the relevant menu items there:

    func textViewDidChangeSelection(textView: UITextView) {
        if self.currentSelectionIsInHighlightedRange() {
            self.setUpUnhighlightMenuItem()
        } else {
            self.setUpHighlightMenuItem()
        }
    }
    
    private func currentSelectionIsInHighlightedRange() -> Bool {
        let allHighlightedRanges = self.document.highlightedRanges()
    
        let selectedTextRange = self.documentView.textView.selectedRange
    
        for range in allHighlightedRanges {
            let intersectionRange = NSIntersectionRange(range, selectedTextRange)
            if intersectionRange.length > 0 {
                return true
            }
        }
        return false
    }