// Subclass UITextView to remove default context menu items like Learn and Share and keep Cut, Copy and Paste
class TextView : UITextView {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
let actions = [#selector(copy(_:)), #selector(cut(_:)), #selector(paste(_:))]
return actions.contains(action)
}
}
I've used the above code to remove excessive menu items and only keep cut/copy/paste but recently there's a new menu item called Search Web that searches the highlighted text in Safari/Google. Is there a way to disable that too?
Remove it in buildMenu(with builder:)
override func buildMenu(with builder: UIMenuBuilder) {
if builder.menu(for: .lookup) != nil {
builder.remove(menu: .lookup)
}
super.buildMenu(with: builder)
}
Related
In a custom UITextView, I override this function:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
But it still shows two menuItems, "Open Link" and "Add to Reading list". I just want to show one "copy" item.
implement the method of UITextViewDelegate below this answer,retun an empty UIMenu that will disable all edit menu, you can try to only add the copy menu.
- (UIMenu *)textView:(UITextView *)textView editMenuForTextInRange:(NSRange)range suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0)) {
return [UIMenu menuWithChildren:#[]];
}
I'm trying to configure UIMenuController's menu items for a functionality similar to Medium's iOS feature:
There are a variety of threads devoted to this specific task, but despite tens of thousands of views and varied results, including it not working for a significant enough number of people... it doesn't seem like there is a solution that works consistently for UITextView.
I have been able to add a custom menu option "printToConsole", but I can't disable Apple's standard menu items like cut, copy, paste, B I U, etc:
The consensus seems to be that I should override canPerformAction to disable these default menu items as such, but that doesn't seem to be working:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
print("canPerformAction being called")
if action == #selector(cut(_:)) {
return false
}
if action == #selector(copy(_:)) {
return false
}
if action == #selector(select(_:)) {
return false
}
if action == #selector(paste(_:)) {
return false
}
if action == #selector(replacementObject(for:)) {
return false
}
if action == #selector(selectAll(_:)) {
return false
}
if action == #selector(printToConsole) {
return true
}
return super.canPerformAction(action, withSender: sender)
}
This is the remainder of my relevant code:
func addCustomMenu() {
let consolePrintAction = UIMenuItem(title: "Print To Console", action: #selector(printToConsole))
UIMenuController.shared.menuItems = [consolePrintAction]
UIMenuController.shared.update()
}
#objc func printToConsole() {
if let range = articleTextView.selectedTextRange, let selectedText = articleTextView.text(in: range) {
print(selectedText)
}
}
And in my viewDidLoad:
articleTextView.delegate = self
addCustomMenu()
I've set my viewController to conform to UITextViewDelegate as well. Some are suggesting that if you simply subclass the TextView this will work somehow. I haven't been able to get that to work, so if that is truly the answer, can someone provide an example?
Again, I know this may seem like a duplicate, but the above solution appears to have stopped working with an update of iOS.
Thanks.
Going to give credit to #gaurav for his answer on this one, which must have escaped me in my hunt on SO: https://stackoverflow.com/a/46470592/7134142
The key piece of code is this, which is extending UITextView, rather than subclassing it:
extension UITextView {
open override func canPerformAction(_ action: Selector, withSender
sender: Any?) -> Bool {
return false
}
Overriding canPerformAction in my view controller was unnecessary, and the above code still allows you to add your custom menu items. This is what I ended up with:
When UITextView's allowsEditingTextAttributes property is enabled,
textView.allowsEditingTextAttributes = true
the textview can show the BIU (bold/italic/underlined) styling options in the context menu by UIMenuController.
UIMenuController - BIU Styling Options #1
UIMenuController - BIU Styling Options #2
I wonder how to add more styling options (e.g., strikethrough, highlight) to the context menu inside the BIU. For example, the iOS' native Notes app has four options (BIU + strikethrough) inside the styling menu.
BIU Styling Options in the native Notes app
Is there any way to do it? I have been spending hours to find a way to override the "Selector(("_showTextStyleOptions:"))" but couldn't find out how.. Please help me!!
When the editing menu is about to become visible, you get a canPerformAction(_:withSender:) call in your UITextView. This method is called again when the user selects a button within the menu. You can check if the font style button was selected and add a custom button to that submenu.
class MyTextView: UITextView {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
let menuController = UIMenuController.shared
if var menuItems = menuController.menuItems,
(menuItems.map { $0.action }).elementsEqual([.toggleBoldface, .toggleItalics, .toggleUnderline]) {
// The font style menu is about to become visible
// Add a new menu item for strikethrough style
menuItems.append(UIMenuItem(title: "Strikethrough", action: .toggleStrikethrough))
menuController.menuItems = menuItems
}
return super.canPerformAction(action, withSender: sender)
}
#objc func toggleStrikethrough(_ sender: Any?) {
print("Strikethrough button was pressed")
}
}
fileprivate extension Selector {
static let toggleBoldface = #selector(MyTextView.toggleBoldface(_:))
static let toggleItalics = #selector(MyTextView.toggleItalics(_:))
static let toggleUnderline = #selector(MyTextView.toggleUnderline(_:))
static let toggleStrikethrough = #selector(MyTextView.toggleStrikethrough(_:))
}
According to documentation, you may have to call update() on the UIMenuController after adding the button. But this was not necessary in my case.
Is it possible to remove the Bold/Italic/Underline selection when highlighting and selecting a text in WKWebView?
Select a word, then press "Select"
The following dialog will present. Notice the "Bold/Italic/Underline" section. How do I remove this?
You should subclass WKWebView and override canPerformAction(_:withSender:) in your subclass.
The selector that displays the bold/italic/underline menu item is called _showTextStyleOptions: and it's an Objective-C method. The double parentheses prevent the compiler from showing a warning that says the method is not accessible.
import WebKit
class CustomWebView: WKWebView {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action != Selector(("_showTextStyleOptions:"))
}
}
This question already has answers here:
How to disable copy paste option from UITextField programmatically
(17 answers)
Closed 5 years ago.
The UITextField's Select, SelectAll, Cut, Copy functionality is shown by default, When I long press or Double Tap on the TextField. I do not require this all features. Please tell me how to disable long press or double tap gesture functionality.
Following code will disable those options:
You have to subclass the UITextField and try to use this code to disable/hide caret and input (copy/paste)
override func caretRectForPosition(position: UITextPosition!) -> CGRect {
return CGRect.zeroRect
}
override func selectionRectsForRange(range: UITextRange) -> [AnyObject] {
return []
}
override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
// Disable copy, select all, paste
if action == Selector("copy:") || action == Selector("selectAll:") || action == Selector("paste:") {
return false
}
// Default
return super.canPerformAction(action, withSender: sender)
}
Here is the swift 3.0 answer,
please try this,
override func canPerformAction(_ action: Selector, withSender sender: Any) -> Bool {
UIMenuController.shared.menuVisible = false
//do not display the menu
self.resignFirstResponder()
//do not allow the user to selected anything
return false
}
Hope this will help you.