chickenparm
chickenparm

Reputation: 1630

Limiting characters and character length in textField(_:shouldChangeCharactersInRange:replacementString:)

I have a username textField in my app that I want to limit to 24 characters and not allow "|" a pipe in the username.

I am able to do each of these individually with the code below but I have having trouble combining these both into textField(_:shouldChangeCharactersInRange:replacementString:).

This code is successfully disallows a "|" in the username field.

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

    if textField === usernameField {
      // Create an `NSCharacterSet` set
      let set = NSCharacterSet(charactersInString:"|")

      // At every character in this "set" contained in the string,
      // split the string up into components which exclude the characters
      // in this inverse set
      let components = string.componentsSeparatedByCharactersInSet(set)

      // Rejoin these components
      let filtered = components.joinWithSeparator("")

      // If the original string is equal to the filtered string, i.e. if no
      // characters were present to be eliminated, the input is valid
      // and the statement returns true; else it returns false
      return string == filtered
    } else {
      return true
    }
  }

This code successfully limits the username field to 24 characters.

  func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    // Added to limit title to <= 40 characters
    guard let text = meetupTitleTextField.text else { return true }

    let newLength = text.utf16.count + string.utf16.count - range.length
    return newLength <= 48 // Bool
  }

I would really appreciate any advice on how to combine these both into textField(_:shouldChangeCharactersInRange:replacementString:)

Upvotes: 0

Views: 815

Answers (2)

Leo Dabus
Leo Dabus

Reputation: 236538

You can create your own custom text field as follow:

import UIKit
@IBDesignable
class LimitedLengthField: UITextField {
    @IBInspectable
    var maxLength: Int = 10 { didSet { editingChanged(self) } }
    override func willMove(toSuperview newSuperview: UIView?) {
        addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        editingChanged(self)
    }
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        editingChanged(self)
    }
    @objc func editingChanged(_ textField: UITextField) {
        textField.text = String(textField.text!.prefix(maxLength))
    }
}

Edit: If you would like to also exclude some characters you can add an ignored characters inspectable property to your field as follow:

import UIKit
@IBDesignable class LimitedLengthField: UITextField {
    @IBInspectable var maxLength: Int = 24 {
        didSet { editingChanged(self) }
    }
    @IBInspectable var ignoredCharacters: String = "|" {
        didSet { editingChanged(self) }
    }
    override func willMove(toSuperview newSuperview: UIView?) {
        addTarget(self, action: #selector(editingChanged), for: .editingChanged)
        editingChanged(self)
    }
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        editingChanged(self)
    }
    @objc func editingChanged(_ textField: UITextField) {
        textField.text = String(text!.filter{!ignoredCharacters.contains($0) }.prefix(maxLength))
    }
}

Upvotes: 2

Code Different
Code Different

Reputation: 93191

Try this:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    if textField == usernameField, let text = textField.text {
        let newLength = text.characters.count + string.characters.count - range.length
        return newLength <= 48 && !string.containsString("|")
    }

    return true
}

Upvotes: 5

Related Questions