Search code examples
swiftswiftuiwkwebviewuimenucontrollerios16

Customize menu : Using UIEditMenuInteraction in WKWebView (iOS 16)


How can we use UIEditMenuInteraction in WkWebViewUITextView to customize menu and add more buttons?

Before iOS 16 I was using:

UIMenuController.shared.menuItems = [menuItem1, menuItem2, menuItem3]

in

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {...}

Thank you


Solution

  • I had the same problem and it took quite a while to find a solution. But, I found I could override buildMenu in MyTextView: UITextView. Here is my code to add a Strikethrough to the menu in iOS 16 and 15

    // This works in iOS 16. I removed some menu items I didn't want as well
    open override func buildMenu(with builder: UIMenuBuilder) {
        if #available(iOS 16.0, *) {
            builder.remove(menu: .lookup) // Lookup, Translate, Search Web
            //builder.remove(menu: .standardEdit) // Cut, Copy, Paste
            builder.remove(menu: .replace) // Replace
            builder.remove(menu: .share) // Share
            //builder.remove(menu: .textStyle) // Format
            // Add new .textStyle action
            let strikethroughAction = UIAction(title: "Strikethough") { action in self.toggleStrikethrough(action.sender)}
            builder.replaceChildren(ofMenu: .textStyle, from: {
                var children = $0
                children.append(strikethroughAction)
                return children
            })
        }
        super.buildMenu(with: builder)
    }
    // This is needed for iOS 15
    open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        if #unavailable(iOS 16.0) {
            let menuController = UIMenuController.shared
            if var menuItems = menuController.menuItems,
               (menuItems.map { $0.title })
                .elementsEqual(["Bold", "Italic", "Underline"]) {
                // The font style menu is about to become visible -- Add a new menu item for strikethrough style
                // Says iOS 16 must use UIEditMenuIteraction instead since UIMenuItem is deprecated in iOS 16
                menuItems.append(UIMenuItem(title: "Strikethrough", action: .toggleStrikethrough))
                menuController.menuItems = menuItems
            }
        }
        return super.canPerformAction(action, withSender: sender)
    }
    

    toggleStrikethrough is a new func I created and added to Selector

    fileprivate extension Selector {
        static let toggleBoldface = #selector(TextView.MyTextView.toggleBoldface(_:))
        static let toggleItalics = #selector(TextView.MyTextView.toggleItalics(_:))
        static let toggleUnderline = #selector(TextView.MyTextView.toggleUnderline(_:))
        static let toggleStrikethrough = #selector(TextView.MyTextView.toggleStrikethrough(_:))
    }
    

    Hope this helps.