How to disable Pasting in a TextField in Swift?

风流意气都作罢 提交于 2019-11-26 19:57:53

问题


I've got a TextField with a number pad and the function runs only if it contains numbers.

The only option that the user will crash the app is if he will paste letters in the TextField and click OK.

How can I disable pasting in the TextField?


回答1:


I agree with Leonardo Savio Dabus, if I were you I'll use string checking and just give out a warning, it makes things easier. BUT, if disabling paste option is a fancy feature you really want to put into your app, then you need to do more work. I'll provide the steps below.

Step 1: You need to create another class which extends the UITextField. In this example, I made my CustomUITextField.

import Foundation
import UIKit  // don't forget this

class CustomUITextField: UITextField {
    override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        if action == "paste:" {
            return false
        }        
        return super.canPerformAction(action, withSender: sender)
    }
}

Step 2: Wire the storyboard with your ViewController. You need to declare an IBOutlet as in normal case:

@IBOutlet var textFieldA: CustomUITextField?

Wire the circle next to the @IBOutlet to the textField in the storyboard. THEN, this is important and easy to be ignored:

  • Go to your storyboard
  • Click the target TextField
  • Select Identity Inspector (the 3rd one)
  • Change the class as CustomUITextField

Quick snapshot is provided below.

That's it, hope this works.

Credit:

Mainly reference from https://teamtreehouse.com/forum/disable-paste-in-uitextfielduitextview-swift

If you want to know more about the behavior of canPerformAction method, though is objective-C version, but the concepts are shared: How can I detect that a user has tapped a formatting button in a UIMenuController?




回答2:


For Swift 3 it's changed to:

override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if action == #selector(copy(_:)) || action == #selector(paste(_:)) {
        return false
    }

    return true
}



回答3:


For Swift 5

UIResponder​Standard​Edit​Actions has been added recently (iOS 10.0+) through which we can safely check if action is "paste" or not.

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)
    }
}



回答4:


Details

  • Xcode 9.1, Swift 4
  • Xcode 10.2 (10E125), 11.2 (11B52), Swift 5

Solution 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)
    }
}

Solution 1 usage

let textField = UITextField(frame: CGRect(x: 50, y: 120, width: 200, height: 50))
textField.borderStyle = .roundedRect
view.addSubview(textField)

Solution 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?[$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)
    }
}

Solution 2 usage

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])

Full sample of the solution 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
    }
}



回答5:


Swift 4.1 this code is working fine with ViewController.

1) Disable all option (copy, paste, delete.....etc)

extension UITextField {

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

2) Enable particular option (select, selectAll... etc)

extension UITextField {

open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    return action == #selector(UIResponderStandardEditActions.select(_:)) || action == #selector(UIResponderStandardEditActions.selectAll(_:))
}



回答6:


You can just attach an IBAction to your Sent Events (editing changed) of your textfield to filter non numbers out of your string as you type as follow:

@IBAction func changedTextAction(sender: UITextField) {
    sender.text = String(Array(sender.text).map{String($0)}.filter{ $0.toInt() != nil }.map{Character($0)} )
}



回答7:


You can create an extension for UITextField and override canPerformAction:

override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
        return (action != "paste:") 
}



回答8:


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
}



回答9:


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
    }
}



回答10:


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)
    }
}



回答11:


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)
    }



回答12:


If you want to Open Date Picker or Picker view on TEXTFIELD click then below code work.

Add below two methods in your 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)
}

//MUST Implement

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
            return false
}


来源:https://stackoverflow.com/questions/29596043/how-to-disable-pasting-in-a-textfield-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!