how to check textfield is not empty and button enable - ios

I want to check textfield is empty
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = (textField.text! as NSString).replacingCharacters(in: range, with: string)
if !text.isEmpty {
self.completeRegisterBtn.isEnabled = true
} else {
self.completeRegisterBtn.isEnabled = false
}
return true
}
This is my code but it is only check input new text.
I have already input textfields by data.
How can i check?
Furthermore not only want to check textfield but also a button(from 2 button) is selected check
Please help me. Thank you

I have attached the code how to check that textFiled is empty or not
let txtField = UITextField()
txtField.text = "testing"
if txtField.text != "" {
btn_Pause.isEnabled = true
} else {
btn_Pause.isEnabled = false
}
-> Using isEmpty function
if txtField.text?.isEmpty == true {
btn_Pause.isEnabled = false
} else {
btn_Pause.isEnabled = true
}
-> Using character count
if txtField.text?.count ?? 0 > 0 {
btn_Pause.isEnabled = true
} else {
btn_Pause.isEnabled = false
}

Answer as per your comment:
if textField.text != "" && btn.isSelected {
}

Just make function like this and call where you want to use this
func dataValidation(text: String) {
btn.isEnable = (text.isEmpty ?? false) ? false : true
}
how to use:
dataValidation(text: "test")

Try this
if let text = textfield.text, !text.isEmpty {
completeRegisterBtn.isEnabled = true
} else {
completeRegisterBtn.isEnabled = false
}

Related

Swift UITextfield Delegate Function "shouldChangeCharactersIn" - How can I stop editing for a second UITextfield?

I have a problem, I have two Textfields and want a max length of 20 Characters for both.
I use the following code but it only works for my first Textfield. What did I wrong? I hope someone can help me.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField === nameTextField {
let currentText = nameTextField.text
guard let stringRange = Range(range, in: currentText!) else {
return false
}
let updateText = currentText?.replacingCharacters(in: stringRange, with: string)
return updateText?.count ?? 0 < 20
} else if textField === numberTextField {
let currentText = numberTextField.text
guard let stringRange = Range(range, in: currentText!) else {
return false
}
let updateText = currentText?.replacingCharacters(in: stringRange, with: string)
return updateText?.count ?? 0 < 20
}
return true
}
You probably forgot to set the delegate for the second one.
Also no need for this complex logic! Just keep the first 20 like:
textView.text = String(textView.text.prefix(20))

Textfield Validation using CharacterSet

I have written below code to validate text input in textfield.
else if (textField == txtField_Password)
{
let charSet = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$&*!")
let charLength = (txtField_Password.text!.count) + (string.count) - range.length
for i in 0..<string.count
{
let c = (string as NSString).character(at: i)
if (!((charSet as NSCharacterSet).characterIsMember(c)))
{
return false
}
}
return (charLength > 20) ? false : true
}
Can anyone help me to convert character(at:) and characterIsMember() part to its swift equivalent in the above code.
You can simplify the logic just by checking the range of the inverted character set. If the string contains only allowed characters the function returns nil.
else if textField == txtField_Password {
let charLength = txtField_Password.text!.utf8.count + string.utf8.count - range.length
let charSet = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$&*!")
return string.rangeOfCharacter(from: charSet.inverted) == nil && charLength < 21
}
Note that there is a simpler way to implement what you want using a regular expression:
let currentText = (textField.text ?? "") as NSString
let newText = currentText.replacingCharacters(in: range, with: string)
let pattern = "^[a-zA-Z0-9#$&*!]{0,20}$"
return newText.range(of: pattern, options: .regularExpression) != nil
You could work with something along these lines. I appreciate this is a bit rough and ready but should work:
charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$&*!"
if txtField_Password.text!.count <= 20 {
for i in 0..<str.count
{
let c = Array(str)[i]
let cString = String(c)
if charSet.contains(cString) {
return false
}
}
} else {
return false
}
Use rangeOfCharacter:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let specialCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$&*!"
let characterSet = CharacterSet(charactersIn: specialCharacters)
guard let lengh = textfield.text else {return}
if lengh.count >= 20 {
// text exceeded 20 characters. Do something
}
if (string.rangeOfCharacter(from: characterSet) != nil) {
print("matched")
return true
} else {
print("not matched")
}
return true
}

How to auto fetch OTP, if we use multiple text fields

I know that if we want to auto fetch the OTP(if we use single textfield) we need to use
otpTextField.textContentType = .oneTimeCode
But, If we use multiple textfield(According to following image)
how should we achieve this ?
-> From iOS 12 Apple will allow the support to read One Time Code which you will get in the iPhone device. you can split text into four fields and autofilled and manually enter otp and remove one by one and move each textfield.
1) self.textone maxmimum length 4 and other textfield max length 1
2) Add UITextFieldDelegate
if #available(iOS 12.0, *) {
txtOne.textContentType = .oneTimeCode
}
self.txtOne.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
self.txtOne.becomeFirstResponder()
#objc func textFieldDidChange(_ textField: UITextField) {
if #available(iOS 12.0, *) {
if textField.textContentType == UITextContentType.oneTimeCode{
//here split the text to your four text fields
if let otpCode = textField.text, otpCode.count > 3{
txtOne.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 0)])
txtTwo.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
txtThree.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
txtFour.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
}
}
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (string.count == 1){
if textField == txtOne {
txtTwo?.becomeFirstResponder()
}
if textField == txtTwo {
txtThree?.becomeFirstResponder()
}
if textField == txtThree {
txtFour?.becomeFirstResponder()
}
if textField == txtFour {
txtFour?.resignFirstResponder()
textField.text? = string
//APICall Verify OTP
//Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.VerifyOTPAPI), userInfo: nil, repeats: false)
}
textField.text? = string
return false
}else{
if textField == txtOne {
txtOne?.becomeFirstResponder()
}
if textField == txtTwo {
txtOne?.becomeFirstResponder()
}
if textField == txtThree {
txtTwo?.becomeFirstResponder()
}
if textField == txtFour {
txtThree?.becomeFirstResponder()
}
textField.text? = string
return false
}
}
I was stuck with Firebase OneTimeCode in 6 different UITextFields and manage to allow the OS to autofill it from Text Message, also to allow the user to copy and paste it and of course to allow the user to insert it one by one by implementing shouldChangeCharactersIn in a very manual but effective way:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//This lines allows the user to delete the number in the textfield.
if string.isEmpty{
return true
}
//----------------------------------------------------------------
//This lines prevents the users from entering any type of text.
if Int(string) == nil {
return false
}
//----------------------------------------------------------------
//This lines lets the user copy and paste the One Time Code.
//For this code to work you need to enable subscript in Strings https://gist.github.com/JCTec/6f6bafba57373f7385619380046822a0
if string.count == 6 {
first.text = "\(string[0])"
second.text = "\(string[1])"
third.text = "\(string[2])"
fourth.text = "\(string[3])"
fifth.text = "\(string[4])"
sixth.text = "\(string[5])"
DispatchQueue.main.async {
self.dismissKeyboard()
self.validCode()
}
}
//----------------------------------------------------------------
//This is where the magic happens. The OS will try to insert manually the code number by number, this lines will insert all the numbers one by one in each TextField as it goes In. (The first one will go in normally and the next to follow will be inserted manually)
if string.count == 1 {
if (textField.text?.count ?? 0) == 1 && textField.tag == 0{
if (second.text?.count ?? 0) == 1{
if (third.text?.count ?? 0) == 1{
if (fourth.text?.count ?? 0) == 1{
if (fifth.text?.count ?? 0) == 1{
sixth.text = string
DispatchQueue.main.async {
self.dismissKeyboard()
self.validCode()
}
return false
}else{
fifth.text = string
return false
}
}else{
fourth.text = string
return false
}
}else{
third.text = string
return false
}
}else{
second.text = string
return false
}
}
}
//----------------------------------------------------------------
//This lines of code will ensure you can only insert one number in each UITextField and change the user to next UITextField when function ends.
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
if count == 1{
if textField.tag == 0{
DispatchQueue.main.async {
self.second.becomeFirstResponder()
}
}else if textField.tag == 1{
DispatchQueue.main.async {
self.third.becomeFirstResponder()
}
}else if textField.tag == 2{
DispatchQueue.main.async {
self.fourth.becomeFirstResponder()
}
}else if textField.tag == 3{
DispatchQueue.main.async {
self.fifth.becomeFirstResponder()
}
}else if textField.tag == 4{
DispatchQueue.main.async {
self.sixth.becomeFirstResponder()
}
}else {
DispatchQueue.main.async {
self.dismissKeyboard()
self.validCode()
}
}
}
return count <= 1
//----------------------------------------------------------------
}
Note: I use a subscript string method in this code, you can get this extension here, String+Subscript.swift
And of course don't forget to assign the delegate and the .oneTimeCode to the TextField.
textField.delegate = self
textField.textContentType = .oneTimeCode
If you can get the auto OTP for single field, you can split that text into your four text fields. I believe.
You may have to use textField's change observer as like below,
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
func textFieldDidChange(_ textField: UITextField) {
// here check you text field's input Type
if textField.textContentType == UITextContentType.oneTimeCode{
//here split the text to your four text fields
if let otpCode = textField.text, otpCode.count > 3{
textField.text = String(otpCode[otpCode.startIndex])
textField1.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
textField2.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
textField3.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
}
}
}
What I do is similar to #Natarajan's answer, but I use UITextFieldDelegate method. On viewDidAppear your first text field should become first responder and be of type oneTimeCode.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Fill your textfields here
return true
}
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.length > 1 {
textFieldDidChange(textField, otpCode: string)
return false
}
}
func textFieldDidChange(_ textField: UITextField, otpCode: String) {
if textField.textContentType == UITextContentType.oneTimeCode{
//here split the text to your four text fields
if otpCode.count == 4, Int(otpCode) != nil {
otp_field_1.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 0)])
otp_field_2.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 1)])
otp_field_3.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 2)])
otp_field_4.text = String(otpCode[otpCode.index(otpCode.startIndex, offsetBy: 3)])
let textFields = [otp_field_1, otp_field_2, otp_field_3, otp_field_4]
for i in 0..<textFields.count{
textFields[i].layer.borderColor = UIColor.GREEN_COLOR.cgColor
}
} else {
textField.text = ""
}
textField.resignFirstResponder()
}
}

Text field not deleting the data when i press `X` button in keyboard

I have 4 UItextfield for enter the top number. Like 1 2 3 4. When I enter the top number in my all text field, and if I am in last urtext field - and if I press backward button or x key in my key board - My number are in each text field are not getting deleted. I was not able to delete.
Here is my code :
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let value = textField.text!
let length = value.characters.count
if (length == 1) {
return false
}
if (textField == Field1) {
self.performSelector(Selector("setNextResponder:"), withObject: Field2, afterDelay: 0.2)
textField1 = string
} else if (textField == Field2) {
self.performSelector(Selector("setNextResponder:"), withObject: Field3, afterDelay: 0.2)
textField2 = string
} else if (textField == Field3) {
self.performSelector(Selector("setNextResponder:"), withObject: Field4, afterDelay: 0.2)
textField3 = string
} else if (textField == Field4) {
textField.resignFirstResponder()
textField4 = string
nextButton.enabled = true
}
else if (textField == Field4)
{
if string == "" && textField.text?.characters.count == 1 {
Field1.text = ""
Field2.text = ""
Field3.text = ""
Field4.text = ""
Field1.becomeFirstResponder()
}
}
return true
}
What i am missing?
You can make it like this:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField.text?.characters.count == 1 && string == "" {
if textField == txt2 {
txt2.text = ""
txt1.becomeFirstResponder()
} else if textField == txt3 {
txt3.text = ""
txt2.becomeFirstResponder()
} else if textField == txt4 {
txt4.text = ""
txt3.becomeFirstResponder()
}
}
return true
}
Still if possible you should create a separate button with clearText action to clear all textfield instead of clearing the textfield from the clear button. It will look as better UI/UX as per the default iOS clear button behaviour
Try :
func textFieldShouldClear(textField: UITextField) -> Bool {
textField.text = ""
textField.resignFirstResponder()
return false
}
Also choose an appropriate option from attribute inspector.

How to limit length of input of Textfield - Swift 2

This code works perfectly, and I can't key in anything other than integers, even when I try to paste it in.
I'd like to add one more refinement, which is to limit the length of the input. Here's my code:
func initializeTextFields()
{
APTeams.delegate = self
APTeams.keyboardType = UIKeyboardType.NumberPad
APRounds.delegate = self
APRounds.keyboardType = UIKeyboardType.NumberPad
APBreakers.delegate = self
APBreakers.keyboardType = UIKeyboardType.NumberPad
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
if text == "" {
return true
}
if let _ = Int(text) {
return true
}
else {
return false
}
}
What do I have to add to it to achieve this? The maximum input length for all the TextFields should be <= 4.
BTW, all code is in Swift 2. From problems I faced when trying to implement answers to questions I've asked before, I gather that some of the methods are different.
count(textField.text) is deprecated in SWIFT 2.0
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let textField = textField as? UITextField {
if (range.length + range.location > textField.text!.characters.count) {
return false;
}
let newLength = textField.text!.characters.count + string.characters.count - range.length;
switch(textField.tag) { //In case you want to handle multiple textfields
case Constants.TAG1:
return newLength <= 20;
case Constants.TAG2:
return newLength <= 30;
default:
return newLength <= 15;
}
}
return true;
}
Write the condition in textfield delegate method as:-
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
if (count(textField.text) > 4 && range.length == 0)
{
return false // return NO to not change text
}
else
{
}
write all your code part in else part.
The delegate methods or an NSFormatter such as NSNumberFormatter.
The formatter is the most appropriate generally as it also provides localization support.
I know its bit too late but still I want share it too, I found a way which is much easier to set a limit character for an textfield in swift development.
Here is the code:-
import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {
#IBInspectable var maxLength: Int {
get {
guard let length = maxLengths[self] else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
addTarget(self, action: #selector(limitLength), for: .editingChanged)
}
}
#objc func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text, prospectiveText.count > maxLength else {
return
}
let selection = selectedTextRange
let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
#if swift(>=4.0)
text = String(prospectiveText[..<maxCharIndex])
#else
text = prospectiveText.substring(to: maxCharIndex)
#endif
selectedTextRange = selection
}
}
and just set the limit through the panel.
Image:
Just try this to limit the length of TF
Editing changed Action Outlet of TF
#IBAction func otpTF2EditingChnaged(_ sender: UITextField) {
if (sender.text?.count == 1) {
otpTF3.becomeFirstResponder()
}
checkMaxLength(textField: sender , maxLength: 1)
}
Function That will limit the length
private func checkMaxLength(textField: UITextField!, maxLength: Int) {
if (textField.text!.count > maxLength) {
textField.deleteBackward()
}
}

Resources