I\'ve got a TextField
with a numberPad
and the function runs only if it contains numbers.
The user will crash the app if they paste letters
I have created a custom class for textField. I have handled the case when you want to enable/disable actions on textfield. You can customize the code as per your requirement. Set isActionsEnabled true/false for enable/disable actions on textfield.
Prefer to use
return super.canPerformAction(action, withSender: sender)
instead of
return true
because returning true might cause a crash in some cases.
Here is my code,
open class MyTextFieldEffect : UITextField {
var isActionsEnabled = true {
didSet {
reloadInputViews()
}
}
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
/* disable particular actions
if (action == #selector(paste(_:)) || action == #selector(copy(_:)) || action == #selector(select(_:)) || action == #selector(cut(_:)) || action == #selector(delete(_:)) || action == #selector(replace(_:withText:)) || action == #selector(select(_:)) || action == #selector(selectAll(_:)) || action == #selector(insertText(_:)) || action == #selector(draw(_:))) && !isActionsEnabled {
return false
}
return super.canPerformAction(action, withSender: sender)
*/
//disable all actions
if !isActionsEnabled {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
Small edit with a code because when you try to use any function like cut or another one the app will crash . The following code tested on swift 3 and working very well
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
I did use this code. This is working.
override func canPerformAction(_ action: Selector, withSender sender: Any?) Bool {
if YOURTEXTFIELD.isFirstResponder {
DispatchQueue.main.async(execute: {
(sender as? UIMenuController)?.setMenuVisible(false, animated: false)
})
return false
}
return super.canPerformAction(action, withSender: sender)
}
You can create an extension for UITextField
and override canPerformAction
:
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
return (action != "paste:")
}
// class TextField: UITextField
extension UITextField {
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.cut) || action == #selector(UIResponderStandardEditActions.copy)
}
}
let textField = UITextField(frame: CGRect(x: 50, y: 120, width: 200, height: 50))
textField.borderStyle = .roundedRect
view.addSubview(textField)
import UIKit
// MARK: Enable/Disable textfield longpress actions
enum ResponderStandardEditActions {
case cut, copy, paste, select, selectAll, delete
case makeTextWritingDirectionLeftToRight, makeTextWritingDirectionRightToLeft
case toggleBoldface, toggleItalics, toggleUnderline
case increaseSize, decreaseSize
var selector: Selector {
switch self {
case .cut:
return #selector(UIResponderStandardEditActions.cut)
case .copy:
return #selector(UIResponderStandardEditActions.copy)
case .paste:
return #selector(UIResponderStandardEditActions.paste)
case .select:
return #selector(UIResponderStandardEditActions.select)
case .selectAll:
return #selector(UIResponderStandardEditActions.selectAll)
case .delete:
return #selector(UIResponderStandardEditActions.delete)
case .makeTextWritingDirectionLeftToRight:
return #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight)
case .makeTextWritingDirectionRightToLeft:
return #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft)
case .toggleBoldface:
return #selector(UIResponderStandardEditActions.toggleBoldface)
case .toggleItalics:
return #selector(UIResponderStandardEditActions.toggleItalics)
case .toggleUnderline:
return #selector(UIResponderStandardEditActions.toggleUnderline)
case .increaseSize:
return #selector(UIResponderStandardEditActions.increaseSize)
case .decreaseSize:
return #selector(UIResponderStandardEditActions.decreaseSize)
}
}
}
class TextField: UITextField {
private var editActions: [ResponderStandardEditActions: Bool]?
private var filterEditActions: [ResponderStandardEditActions: Bool]?
func setEditActions(only actions: [ResponderStandardEditActions]) {
if self.editActions == nil { self.editActions = [:] }
filterEditActions = nil
actions.forEach { self.editActions?[$0] = true }
}
func addToCurrentEditActions(actions: [ResponderStandardEditActions]) {
if self.filterEditActions == nil { self.filterEditActions = [:] }
editActions = nil
actions.forEach { self.filterEditActions?[$0] = true }
}
private func filterEditActions(actions: [ResponderStandardEditActions], allowed: Bool) {
if self.filterEditActions == nil { self.filterEditActions = [:] }
editActions = nil
actions.forEach { self.filterEditActions?[$0] = allowed }
}
func filterEditActions(notAllowed: [ResponderStandardEditActions]) {
filterEditActions(actions: notAllowed, allowed: false)
}
func resetEditActions() { editActions = nil }
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if let actions = editActions {
for _action in actions where _action.key.selector == action { return _action.value }
return false
}
if let actions = filterEditActions {
for _action in actions where _action.key.selector == action { return _action.value }
}
return super.canPerformAction(action, withSender: sender)
}
}
let textField = TextField(frame: CGRect(x: 50, y: 50, width: 200, height: 50))
textField.borderStyle = .roundedRect
view.addSubview(textField)
textField.setEditActions(only: [.copy, .cut, .paste])
//textField.filterEditActions(notAllowed: [.copy, .cut, .paste])
//textField.addToCurrentEditActions(actions: [.paste])
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addTextField(y: 50)
addTextField(y: 100).setEditActions(only: [.copy, .cut, .paste])
addTextField(y: 150).filterEditActions(notAllowed: [.copy, .cut, .paste])
}
@discardableResult func addTextField(y: CGFloat) -> TextField {
let textField = TextField(frame: CGRect(x: 50, y: y, width: 200, height: 34))
textField.borderStyle = .roundedRect
textField.text = "Text"
view.addSubview(textField)
return textField
}
}
In the actual swift version(2.2 going to 3.0) this function code must be refactored to:
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
if action == #selector(NSObject.copy(_:)) || action == #selector(NSObject.paste(_:)) {
return false
}
return true
}