如何在 Swift 的 TextField 中禁用粘贴?
How to disable pasting in a TextField in Swift?
我有一个 TextField
和一个 numberPad
,只有当它包含数字时函数才会运行。
如果用户在 TextField
中粘贴字母并单击确定,用户将导致应用程序崩溃。
如何在 TextField
中禁用粘贴?
您可以将 IBAction 附加到文本字段的已发送事件(编辑已更改),以在您键入时从文本中删除所有非数字,如下所示:
@IBAction func editingChanged(_ textField: UITextField) {
textField.text?.removeAll { !("0"..."9" ~= [=10=]) }
}
这将允许用户粘贴到字段中,但它会从字符串中过滤掉所有非数字。
我同意 ,如果我是你,我会使用字符串检查并发出警告,这会让事情变得更容易。但是,如果禁用粘贴选项是您真正想要放入应用程序中的奇特功能,那么您需要做更多的工作。我将提供以下步骤。
第 1 步:您需要创建另一个 class 来扩展 UITextField
。在这个例子中,我做了 CustomUITextField
.
import Foundation
import UIKit //Don't forget this
class CustomUITextField: UITextField {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.paste(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
第 2 步:使用您的 ViewController 连接故事板。您需要像正常情况一样声明一个 IBOutlet
:
@IBOutlet var textFieldA: CustomUITextField?
将 @IBOutlet
旁边的圆圈连接到故事板中的 TextField
。那么,这很重要也很容易被忽略:
- 转到你的故事板
- 点击目标
TextField
- Select Identity Inspector(第三个)
- 将 class 更改为
CustomUITextField
下面提供了快速快照。
就是这样,希望这有效。
来源:
如果您想了解更多关于 canPerformAction
方法的行为,虽然它是 Objective-C 版本,但概念是共享的 here。
您可以为 UITextField
创建扩展并覆盖 canPerformAction
:
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
return (action != "paste:")
}
在实际的swift版本中(2.2转3.0)这个功能代码必须重构为:
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
if action == #selector(NSObject.copy(_:)) || action == #selector(NSObject.paste(_:)) {
return false
}
return true
}
对于Swift 3它改为:
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
return false
}
return true
}
对于Swift 5
最近添加了 UIResponderStandardEditActions
(iOS 10.0+),通过它我们可以安全地检查操作是否为 "paste"。
import UIKit
class NMTextField: UITextField {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.paste(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
使用代码进行小修改,因为当您尝试使用任何功能(如剪切或其他功能)时,应用程序会崩溃。以下代码在 swift 3 上测试并且运行良好
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)
}
详情
- Xcode9.1,Swift4
- Xcode 10.2 (10E125), 11.2 (11B52), Swift 5
解决方案 1
// class TextField: UITextField
extension UITextField {
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.cut) || action == #selector(UIResponderStandardEditActions.copy)
}
}
解决方案 1 用法
let textField = UITextField(frame: CGRect(x: 50, y: 120, width: 200, height: 50))
textField.borderStyle = .roundedRect
view.addSubview(textField)
解决方案 2
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?[[=12=]] = true }
}
func addToCurrentEditActions(actions: [ResponderStandardEditActions]) {
if self.filterEditActions == nil { self.filterEditActions = [:] }
editActions = nil
actions.forEach { self.filterEditActions?[[=12=]] = true }
}
private func filterEditActions(actions: [ResponderStandardEditActions], allowed: Bool) {
if self.filterEditActions == nil { self.filterEditActions = [:] }
editActions = nil
actions.forEach { self.filterEditActions?[[=12=]] = 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)
}
}
解决方案 2 用法
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])
解决方案 2 的完整示例
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
}
}
class CustomUITextField: UITextField {
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(cut(_:)) ||
action == #selector(copy(_:)) ||
action == #selector(UIResponderStandardEditActions.paste(_:)) ||
action == #selector(UIResponderStandardEditActions.select(_:)) ||
action == #selector(UIResponderStandardEditActions.selectAll(_:)) ||
action == #selector(UIResponderStandardEditActions.delete(_:)) ||
action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight(_:)) ||
action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleBoldface(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleItalics(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleUnderline(_:)) ||
action == #selector(UIResponderStandardEditActions.increaseSize(_:)) ||
action == #selector(UIResponderStandardEditActions.decreaseSize(_:))
{
return false
};
return true
}
}
我已经为 textField 创建了自定义 class。当您想对文本字段执行 enable/disable 操作时,我已经处理过这种情况。您可以根据需要自定义代码。为文本字段上的 enable/disable 操作设置 isActionsEnabled true/false。
更喜欢使用
return super.canPerformAction(action, withSender: sender)
而不是
return true
因为在某些情况下返回 true 可能会导致崩溃。
这是我的代码,
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)
}
}
Swift 4.1 此代码在 ViewController.
下运行良好
1) 禁用所有选项(复制、粘贴、删除......等)
extension UITextField {
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
}
2) 启用特定选项(select、select全部...等)
extension UITextField {
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.select(_:)) || action == #selector(UIResponderStandardEditActions.selectAll(_:))
}
如果您想在 TEXTFIELD 上打开日期选择器或选择器视图,请单击下面的代码。
在您的 class 中添加以下两种方法。
//Hide Menu View
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)
}
//必须实施
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return false
}
Swift 5
如果您想阻止应用中每个文本字段的粘贴操作
extension UITextField {
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.paste(_:)) ?
false : super.canPerformAction(action, withSender: sender)
}
}
编辑
如果要阻止将选择器作为输入视图的文本字段的粘贴操作,请添加 guard
,如下所示:
extension UITextField {
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
guard inputView != nil else { return super.canPerformAction(action, withSender: sender) }
return action == #selector(UIResponderStandardEditActions.paste(_:)) ?
false : super.canPerformAction(action, withSender: sender)
}
}
警告:第二种解决方案将允许用户粘贴数字字段。
我确实用过这段代码。这是有效的。
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)
}
我有一个 TextField
和一个 numberPad
,只有当它包含数字时函数才会运行。
如果用户在 TextField
中粘贴字母并单击确定,用户将导致应用程序崩溃。
如何在 TextField
中禁用粘贴?
您可以将 IBAction 附加到文本字段的已发送事件(编辑已更改),以在您键入时从文本中删除所有非数字,如下所示:
@IBAction func editingChanged(_ textField: UITextField) {
textField.text?.removeAll { !("0"..."9" ~= [=10=]) }
}
这将允许用户粘贴到字段中,但它会从字符串中过滤掉所有非数字。
我同意
第 1 步:您需要创建另一个 class 来扩展 UITextField
。在这个例子中,我做了 CustomUITextField
.
import Foundation
import UIKit //Don't forget this
class CustomUITextField: UITextField {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.paste(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
第 2 步:使用您的 ViewController 连接故事板。您需要像正常情况一样声明一个 IBOutlet
:
@IBOutlet var textFieldA: CustomUITextField?
将 @IBOutlet
旁边的圆圈连接到故事板中的 TextField
。那么,这很重要也很容易被忽略:
- 转到你的故事板
- 点击目标
TextField
- Select Identity Inspector(第三个)
- 将 class 更改为
CustomUITextField
下面提供了快速快照。
就是这样,希望这有效。
来源:
如果您想了解更多关于 canPerformAction
方法的行为,虽然它是 Objective-C 版本,但概念是共享的 here。
您可以为 UITextField
创建扩展并覆盖 canPerformAction
:
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
return (action != "paste:")
}
在实际的swift版本中(2.2转3.0)这个功能代码必须重构为:
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
if action == #selector(NSObject.copy(_:)) || action == #selector(NSObject.paste(_:)) {
return false
}
return true
}
对于Swift 3它改为:
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
return false
}
return true
}
对于Swift 5
最近添加了UIResponderStandardEditActions
(iOS 10.0+),通过它我们可以安全地检查操作是否为 "paste"。
import UIKit
class NMTextField: UITextField {
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.paste(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}
使用代码进行小修改,因为当您尝试使用任何功能(如剪切或其他功能)时,应用程序会崩溃。以下代码在 swift 3 上测试并且运行良好
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)
}
详情
- Xcode9.1,Swift4
- Xcode 10.2 (10E125), 11.2 (11B52), Swift 5
解决方案 1
// class TextField: UITextField
extension UITextField {
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.cut) || action == #selector(UIResponderStandardEditActions.copy)
}
}
解决方案 1 用法
let textField = UITextField(frame: CGRect(x: 50, y: 120, width: 200, height: 50))
textField.borderStyle = .roundedRect
view.addSubview(textField)
解决方案 2
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?[[=12=]] = true }
}
func addToCurrentEditActions(actions: [ResponderStandardEditActions]) {
if self.filterEditActions == nil { self.filterEditActions = [:] }
editActions = nil
actions.forEach { self.filterEditActions?[[=12=]] = true }
}
private func filterEditActions(actions: [ResponderStandardEditActions], allowed: Bool) {
if self.filterEditActions == nil { self.filterEditActions = [:] }
editActions = nil
actions.forEach { self.filterEditActions?[[=12=]] = 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)
}
}
解决方案 2 用法
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])
解决方案 2 的完整示例
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
}
}
class CustomUITextField: UITextField {
override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(cut(_:)) ||
action == #selector(copy(_:)) ||
action == #selector(UIResponderStandardEditActions.paste(_:)) ||
action == #selector(UIResponderStandardEditActions.select(_:)) ||
action == #selector(UIResponderStandardEditActions.selectAll(_:)) ||
action == #selector(UIResponderStandardEditActions.delete(_:)) ||
action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionLeftToRight(_:)) ||
action == #selector(UIResponderStandardEditActions.makeTextWritingDirectionRightToLeft(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleBoldface(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleItalics(_:)) ||
action == #selector(UIResponderStandardEditActions.toggleUnderline(_:)) ||
action == #selector(UIResponderStandardEditActions.increaseSize(_:)) ||
action == #selector(UIResponderStandardEditActions.decreaseSize(_:))
{
return false
};
return true
}
}
我已经为 textField 创建了自定义 class。当您想对文本字段执行 enable/disable 操作时,我已经处理过这种情况。您可以根据需要自定义代码。为文本字段上的 enable/disable 操作设置 isActionsEnabled true/false。
更喜欢使用
return super.canPerformAction(action, withSender: sender)
而不是
return true
因为在某些情况下返回 true 可能会导致崩溃。
这是我的代码,
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)
}
}
Swift 4.1 此代码在 ViewController.
下运行良好1) 禁用所有选项(复制、粘贴、删除......等)
extension UITextField {
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
}
2) 启用特定选项(select、select全部...等)
extension UITextField {
open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.select(_:)) || action == #selector(UIResponderStandardEditActions.selectAll(_:))
}
如果您想在 TEXTFIELD 上打开日期选择器或选择器视图,请单击下面的代码。
在您的 class 中添加以下两种方法。
//Hide Menu View
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)
}
//必须实施
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
return false
}
Swift 5
如果您想阻止应用中每个文本字段的粘贴操作
extension UITextField {
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.paste(_:)) ?
false : super.canPerformAction(action, withSender: sender)
}
}
编辑
如果要阻止将选择器作为输入视图的文本字段的粘贴操作,请添加 guard
,如下所示:
extension UITextField {
override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
guard inputView != nil else { return super.canPerformAction(action, withSender: sender) }
return action == #selector(UIResponderStandardEditActions.paste(_:)) ?
false : super.canPerformAction(action, withSender: sender)
}
}
警告:第二种解决方案将允许用户粘贴数字字段。
我确实用过这段代码。这是有效的。
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)
}