TransWikia.com

How to disable pasting in a TextField in Swift?

Stack Overflow Asked by Eliko on November 26, 2020

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 in the TextField and click OK.

How can I disable pasting in the TextField?

14 Answers

I agree with Leonardo Savio Dabus, if I were you I'd 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: Any?) -> Bool {
        if action == #selector(UIResponderStandardEditActions.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 to CustomUITextField

Quick snapshot is provided below.

enter image description here

That's it, hope this works.

Credit:

Main reference

If you want to know more about the behavior of canPerformAction method, though it's an Objective-C version, the concepts are shared here.

Correct answer by TimeString on November 26, 2020

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

Answered by Sameen Ahmad on November 26, 2020

Swift 5

If you want to block paste action from every text field in your app

extension UITextField {
    override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.paste(_:)) ?
            false : super.canPerformAction(action, withSender: sender)
    }
}

EDIT

If you want to block the paste action for text fields that have pickers as input view, add a guard like the following:

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

Warning: the second solution will allow the user to paste on numeric fields.

Answered by Matias Jurfest on November 26, 2020

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
}

Answered by Renish Dadhaniya on November 26, 2020

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(_:))
}

Answered by Harikant Amipara on November 26, 2020

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

Answered by Pramod More on November 26, 2020

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

Answered by Tejash Joshi on November 26, 2020

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

Answered by Vasily Bodnarchuk on November 26, 2020

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

Answered by waleed alghamdi on November 26, 2020

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

Answered by Nikhil Manapure on November 26, 2020

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
}

Answered by Andrey Gordeev on November 26, 2020

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
}

Answered by dede.exe on November 26, 2020

You can create an extension for UITextField and override canPerformAction:

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

Answered by zaltzy on November 26, 2020

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 = sender.text?.filter(.isWholeNumber)
}

This will allow the user to paste into the field but it will filter all non digits from the string.

Answered by Leo Dabus on November 26, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP