1

Is there a way to limit a UITextField to only numeric value as well as limiting the length.

I have the below two functions but don't know how I can use the shouldChangeCharactersIn twice in the same delegate. Any ideas how to use both of these

 // Allow Numeric Only in Quantity
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,     replacementString string: String) -> Bool {
    let allowCharacters = ".-+1234567890"
    let allowedCharacterSet = CharacterSet(charactersIn: allowCharacters)
    let typedCharacterSet = CharacterSet(charactersIn: string)

    return allowedCharacterSet.isSuperset(of: typedCharacterSet)
}



// Limit the length of the input
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let textFieldText = textField.text,
        let rangeOfTextToReplace = Range(range, in: textFieldText) else {
            return false
    }

    let substringToReplace = textFieldText[rangeOfTextToReplace]
    let count = textFieldText.count - substringToReplace.count + string.count
    return count <= 20
}

Many Thanks

  • Does this answer your question? [Set the maximum character length of a UITextField](https://stackoverflow.com/questions/433337/set-the-maximum-character-length-of-a-uitextfield) – Cing May 23 '20 at 11:32

1 Answers1

0

You can do it like this

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

   guard let textFieldText = textField.text,
       let rangeOfTextToReplace = Range(range, in: textFieldText) else {
               return false
       }

   let substringToReplace = textFieldText[rangeOfTextToReplace]
   let count = textFieldText.count - substringToReplace.count + string.count

   let allowedCharacters = ".-+1234567890"
   let allowedCharcterSet = CharacterSet(charactersIn: allowedCharacters)
   let typedCharcterSet = CharacterSet(charactersIn: string)

        if  allowedCharcterSet.isSuperset(of: typedCharcterSet)
                   , count <= 20 {
                 return true
              } else {
                 return false
              }
 }

Or you can use this Subclass of UITextField

class JDTextField: UITextField {

    @IBInspectable var maxLength: Int = 0 // Max character length
    var valueType: ValueType = ValueType.none // Allowed characters

    /************* Added new feature ***********************/
    // Accept only given character in string, this is case sensitive
    @IBInspectable var allowedCharInString: String = ""

    func verifyFields(shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        switch valueType {
        case .none:
            break // Do nothing

        case .onlyLetters:
            let characterSet = CharacterSet.letters
            if string.rangeOfCharacter(from: characterSet.inverted) != nil {
                return false
            }

        case .onlyNumbers:
            let numberSet = CharacterSet.decimalDigits
            if string.rangeOfCharacter(from: numberSet.inverted) != nil {
                return false
            }

        case .phoneNumber:
            let phoneNumberSet = CharacterSet(charactersIn: "+0123456789")
            if string.rangeOfCharacter(from: phoneNumberSet.inverted) != nil {
                return false
            }

        case .alphaNumeric:
            let alphaNumericSet = CharacterSet.alphanumerics
            if string.rangeOfCharacter(from: alphaNumericSet.inverted) != nil {
                return false
            }

        case .fullName:
            var characterSet = CharacterSet.letters
            print(characterSet)
            characterSet = characterSet.union(CharacterSet(charactersIn: " "))
            if string.rangeOfCharacter(from: characterSet.inverted) != nil {
                return false
            }
        }

        if let text = self.text, let textRange = Range(range, in: text) {
            let finalText = text.replacingCharacters(in: textRange, with: string)
            if maxLength > 0, maxLength < finalText.utf8.count {
                return false
            }
        }

        // Check supported custom characters
        if !self.allowedCharInString.isEmpty {
            let customSet = CharacterSet(charactersIn: self.allowedCharInString)
            if string.rangeOfCharacter(from: customSet.inverted) != nil {
                return false
            }
        }

        return true
    }
}

How to use it

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    // Verify all the conditions
    if let sdcTextField = textField as? JDTextField {
        return sdcTextField.verifyFields(shouldChangeCharactersIn: range, replacementString: string)
    } else {
        return true
    }
}

And in viewDidLoad() you set characteristics in just one line

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    self.textField.delegate = self
    self.textField.maxLength = 10
    self.textField.allowedCharInString = ".-+1234567890"
}
Jawad Ali
  • 13,556
  • 3
  • 32
  • 49