I have a textField to input a Canadian postal code. And I am using the following code to ensure the formatting is correct or else show an alert saying the formatting is incorrect. This is working with no problem on saveBtnClick; but I cant type in the field as it continues returning false into the textField because of the validZipCode function.I also need make sure the maximum length of characters for this field does not exceed 7 characters so the user cant type more than seven characters. I see many solutions only for setting the maximum length; but cant figure out how to do this with an existing condition that I mentioned here for postal code validation. Here is my current code:
#IBOutlet weak var postalCodeTextField: UITextField!
override func viewDidLoad() {
phoneNumberTextField.delegate = self
postalCodeTextField.delegate = self
}
func validZipCode(postalCode:String)->String{
let postalcodeRegex = "^[a-zA-Z][0-9][a-zA-Z][- ]*[0-9][a-zA-Z][0-9]$"
let pinPredicate = NSPredicate(format: "SELF MATCHES %#", postalcodeRegex)
let bool = pinPredicate.evaluate(with: postalCode) as Bool
return bool.description
}
#IBAction func saveBtnClicked(_ sender: Any) {
let isPostalCodeValid = validZipCode(postalCode: postalCodeTextField.text ?? "")
if isPostalCodeValid == "false" {
simpleAlert(title: "Error!", msg: "Please enter a valid CA postal code")
} else
if isPostalCodeValid == "true" {
//the postalCaode is correct formatting
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return false }
let newString = (text as NSString).replacingCharacters(in: range, with: string)
if textField == phoneNumberTextField {
textField.text = formattedNumber(number: newString)
} else
if textField == postalCodeTextField {
textField.text = validZipCode(postalCode: newString)
}
return false
}
The function validZipCode would always return false if we pass single character to it. So ,validate the predicate on click of saveButton.
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var postalCodeTextField: UITextField!
override func viewDidLoad() {
postalCodeTextField.delegate = self
}
func validZipCode(postalCode:String)->Bool{
let postalcodeRegex = "^[a-zA-Z][0-9][a-zA-Z][- ]*[0-9][a-zA-Z][0-9]$"
let pinPredicate = NSPredicate(format: "SELF MATCHES %#", postalcodeRegex)
let bool = pinPredicate.evaluate(with: postalCode) as Bool
return bool
}
#IBAction func saveBtnClicked(_ sender: Any) {
let isPostalCodeValid = validZipCode(postalCode: postalCodeTextField.text ?? "")
if isPostalCodeValid == false {
print("false")
// simpleAlert(title: "Error!", msg: "Please enter a valid CA postal code")
} else
if isPostalCodeValid == true {
print("true")
//the postalCaode is correct formatting
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentText = textField.text ?? ""
guard let stringRange = Range(range, in: currentText) else { return false }
if textField == postalCodeTextField {
// add their new text to the existing text
let updatedText = currentText.replacingCharacters(in: stringRange, with: string)
// make sure the result is under 7 characters
return updatedText.count <= 7
}else{
return true
}
}
}
Hope this helps !!
Related
I need to specify a maximum value for a text field. I already got an answer from another post on how to restrict a UITextField to numbers only. But I would like to modify that function to only accept a number between 0 and 540.
Is there any way to modify that function?
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let s = NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)
guard !s.isEmpty else { return true }
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .none
return numberFormatter.number(from: s)?.intValue != nil
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
print(string)
let myRange = 0...540
//ro delete/remove values in textField
if string == "" {
return true
}
let fullText = NSString(string: textField.text ?? "").replacingCharacters(in: range, with: string)
if let wholeNumber = Int(fullText), myRange.contains(wholeNumber) {
return true
}
return false
}
You can check if number lies between 0 and 540.
if let number = numberFormatter.number(from: s)?.intValue {
return number > 0 && number < 540
} else {
return true
}
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
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"
}
How to limit the number of characters in a UITextField?
I need to to display max 10 characters
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let textFieldCadena = textField.text, let range = Range(range, in: textFieldCadena) else {
return false
}
let nuevaCadena = textFieldCadena.replacingCharacters(in: range, with: string)
if nuevaCadena.isEmpty {
textField.text = "0"
return false
} else if textField.text == "0" {
textField.text = string
return false
}
if textField == textField {
let allowedCharacters = CharacterSet(charactersIn:"0123456789 ")
let characterSet = CharacterSet(charactersIn: string)
return allowedCharacters.isSuperset(of: characterSet)
}
return true
}
As decribed here You can use .maxlength in swift 5 to set character length. Credit to article here:
https://www.swiftdevcenter.com/max-character-limit-of-uitextfield-and-allowed-characters-swift/
self.textField.maxLength = 10
Do the check for character count first
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard
let textFieldCadena = textField.text,
let range = Range(range, in: textFieldCadena),
textFieldCadena.count <= 10
else { return false }
...
}
How can i add another condition to my function, for another textfield and how to make this code is more simple
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let text = textField.text {
if let floatingLabelTextField = textField as? SkyFloatingLabelTextField {
if(text.characters.count < 3 || !text.containsString("#")) {
floatingLabelTextField.errorMessage = "Invalid email"
}
else {
// The error message will only disappear when we reset it to nil or empty string
floatingLabelTextField.errorMessage = ""
}
}
}
return true
}
Below code will be more simpler and easy to add any new condition:
func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: testStr)
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else{
return true
}
guard let floatingLabelTextField = textField as? SkyFloatingLabelTextField else {
return true
}
if isValidEmail(testStr: text) {
floatingLabelTextField.errorMessage = ""
}else{
floatingLabelTextField.errorMessage = "Invalid email"
}
return true
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
if textField == textField as? SkyFloatingLabelTextField && (!textField.text.containsString("#") || textField.text.characters.count < 3 )
{
floatingLabelTextField.errorMessage = "Invalid email"
}
else
{
floatingLabelTextField.errorMessage = ""
}
return true
}
You can check firstly if textfield is your selected textfield and in same condition you can also check email validation.
In my app, I have 2 text fields. taskTextField and DescTextField. I would like to limit the characters of the task text field to 15 and the description text field to 20. I have managed to limit both but I don't know how to do them separately. Here is my code for both:
let limitLength = 20
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else { return true }
let newLength = text.characters.count + string.characters.count - range.length
return newLength <= limitLength
}
Any help on how to make separate limits for each text field would be appreciated.
Add a tag for each UITextField:
let taskTextFieldTag = 100
let DescTextFieldTag = 101
override func viewDidLoad() {
// ..
taskTextField.tag = taskTextFieldTag
DescTextField.tag = DescTextFieldTag
// ...
}
In the UITextFieldDelegate:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let text = textField.text else {
return false
}
let newLength = text.utf16.count + string.utf16.count - range.length
var maxLength = 0
switch textField.tag {
case taskTextFieldTag:
maxLength = 15
case DescTextFieldTag:
maxLength = 20
default: break
}
return newLength <= maxLength
}
Based on your code assuming you can connect the text fields to your code via IBOutlets
#IBOutlet weak var taskTextField: UITextField!
#IBOutlet weak var descTextField: UITextField!
let taskTextFieldlimitLength = 15
let descTextFieldlimitLength = 20
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
switch textField {
case taskTextField:
guard let text = textField.text else { return true }
let newLength = text.characters.count + string.characters.count - range.length
return newLength <= taskTextFieldlimitLength
case descTextField:
guard let text = textField.text else { return true }
let newLength = text.characters.count + string.characters.count - range.length
return newLength <= descTextFieldlimitLength
default:
return true
}
}