Issue with limiting characters in textfield - ios

This is how I am limiting the characters entered in two textFields...
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == textField1 {
if (textField1.text?.characters.count)! + (string.characters.count - range.length) > 11 {
return false
}
return true
} else if textField == textField2 {
if (textField2.text?.characters.count)! + (string.characters.count - range.length) > 15 {
return false
}
}
return true
}
But the issue is only textField1 is not allowing to enter more than 11 characters but textField2 is accepting any number of characters while it should not have allowed to enter more than 15 characters.

Since there's nothing wrong with your code, you can try following check list:
Check if textfield 2 outlet is set. You can do it manually or
you can try adding a breakpoint (or print) in you else if textField == textField2 {} block
Also check if delegate of textField2 is set to self as well
If control comes to else if block then your code must work.

I think you haven't set the delegate in viewDidLoad,
import UIKit
class ViewController: UIViewController, UITextFieldDelegate{
#IBOutlet var textField1 :UITextField!
#IBOutlet var textField2 :UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.textField1.delegate = self
self.textField2.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == textField1 {
if (textField1.text?.characters.count)! + (string.characters.count - range.length) > 11 {
return false
}
return true
} else if textField == textField2 {
if (textField2.text?.characters.count)! + (string.characters.count - range.length) > 11 {
return false
}
}
return true
}

Maybe you forgot to set textField2's delegate,And I did a test,your code is work!

Related

Move from one text field to another

How can I make text field-1 move to another text field-2 by Swift when I write two numbers?
When I write 22, I want to automatically move to another text field-2.
I tried this but it doesn't work:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let text = textField.text {
let newStr = (text as NSString)
.stringByReplacingCharactersInRange(range, withString: string)
if newStr.isEmpty {
return true
}
let intvalue = Int(newStr)
if textField.tag == 101 { print("101") // only 2 integer
return (intvalue >= 0 && intvalue <= 99) ? true : false
}
else if textField.tag == 102 { print("102") // only 4 integer
return (intvalue >= 0 && intvalue <= 9999) ? true : false
}
}
return true
}
textField.addTarget(self, action: #selector(textDidChanged(textField:)), for: .editingChanged)
func textDidChanged(textField: UITextField)
{
if (textField.text) == "22"
{
newTextField.becomeFirstResponder()
}
}
add delegate to both the textfields
also add UITextFieldDelegate to your viewcontroller
Create IBAction for both textfields like this and check first textfield's characters count in IBAction. If count is 2 second textfield will become active.
#IBAction func textEntered(_ sender: UITextField) {
if sender.tag == 101 && sender.text?.characters.count == 2
{
(self.view.subviews.first(where: { $0.tag == 102 }) as! UITextField).becomeFirstResponder()
}
}
You should add a target for editingChanged event of your textField like below or simply drag an action from storyboard in to your class :
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
then in your selector do as follow :
func textFieldDidChange(_ textField: UITextField) {
if textField.tag == 101 && textField.text!.characters.count >= 2 {
secondTextField.becomeFirstResponder()
}
}
No need to do more,
just modify your shouldChangeCharactersIn range
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let finalText = (textField.text ?? "")// + string
if textField === self.textField1! && finalText.characters.count >= 2 {
self.textField1.resignFirstResponder()
self.textField2.becomeFirstResponder()
return false
}
else if textField === self.textField2! && finalText.characters.count >= 4 {
self.textField2.resignFirstResponder()
self.textField1.becomeFirstResponder()
return false
}
return true
}
Try not to use the tag in the code as it's not understandable to other programmers after you on the project.

Use UITextFieldDelegate for multiple fields

I have the following code to prevent the user from entering more than one period . in a UITextField, it works fine but I would like to do the same with other two textFields, how can this be done?
I tried assigning delegate to multiple fields and it doesn't quite work, it only works on the first to be comes the first responded.
class UserInputViewController: UIViewController, UITextFieldDelegate{
override func viewDidLoad() {
super.viewDidLoad()
self.myTextField.delegate = self
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let periodsInTextField = myTextField.text!.componentsSeparatedByString(".").count - 1
if (periodsInTextField > 0 && string == "."){
return false
}
return true
}
}
EDIT(Answer) : Here is how it should be done based on # KKRocks' answer below.
class UserInputViewController: UIViewController, UITextFieldDelegate{
override func viewDidLoad() {
super.viewDidLoad()
self.myTextField.delegate = self
self.secondTextField.delegate = self
self.thirdTextField.delegate = self
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let periodsInTextField = textField.text!.componentsSeparatedByString(".").count - 1
if (periodsInTextField > 0 && string == "."){
return false
}
return true
}
}
Please change this line with
From :
let periodsInTextField = myTextField.text!.componentsSeparatedByString(".").count - 1
To :
let periodsInTextField = textField.text!.componentsSeparatedByString(".").count - 1

Change UITextField responder on Max Length

I have login controller where it has two textFields:
Access Card
Password
The Max Length for the access card is 9 and once the user type the ninth number, it should appear on the access card filed then the cursor needs to move to the password field.
In my code, the cursor is moving when the user clicks to enter the ninth number but the number doesn't appear and the cursor moves to the password field.
For example: I want to enter "123456789" as access card. Once I click "9" it doesn't appear but the cursor moves to password field:
LoginController.swift:
let ACCESSCARD_MAXLENGTH = 9
let PASSWORD_MAXLENGTH = 12
var AccessCardtextFieldLength = 0
var PasswordTextFieldLength = 0
class LoginViewController: UIViewController , UITextFieldDelegate {
#IBOutlet weak var AccessCardTextField: UITextField!
#IBOutlet weak var PasswordTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// calling the function that initialize textFields
initializeTextFields()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// function is used to initialize textFields
func initializeTextFields () {
// To set the focus on the access card once the view load.
AccessCardTextField.becomeFirstResponder()
// This must be defined so we can apply the text field functions on it
AccessCardTextField.delegate = self
PasswordTextField.delegate = self
// Define the keyboard type of the textFields.
AccessCardTextField.keyboardType = UIKeyboardType.NumberPad
PasswordTextField.keyboardType = UIKeyboardType.ASCIICapable
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
AccessCardtextFieldLength = (textField.text?.characters.count)! + string.characters.count
PasswordTextFieldLength = (textField.text?.characters.count)! + string.characters.count
if (textField == AccessCardTextField){
for i in 0..<ACCESSCARD_MAXLENGTH{
if (AccessCardtextFieldLength == ACCESSCARD_MAXLENGTH){
PasswordTextField.becomeFirstResponder()
}
else{
return true
}
return false
}
}
if (textField == PasswordTextField){
return PasswordTextFieldLength <= PASSWORD_MAXLENGTH ? true : false
}
return true
}
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool will only update when it return true. In this case you are changing the firstResponder therefore it is not updated.
My suggestion is to use add target for this case. This is what you can do:
override func viewDidLoad() {
super.viewDidLoad()
// calling the function that initialize textFields
initializeTextFields()
accessCardTextField.addTarget(self, action: #selector(LoginViewController.accessCardTextFieldChanged(_:)), forControlEvents: .EditingChanged)
}
func accessCardTextFieldChanged(textField: UITextField) {
if textField.text?.characters.count == ACCESSCARD_MAXLENGTH {
modelTextField.becomeFirstResponder()
}
}
This way, it save you quite a few line of code. Most importantly, only accessCardTextField changed will be call. You could do another function to check your password textfield length separately. Also, i renamed from AccessCardTextField to accessCardTextField. It is recommended to have variable starting with lower case.
Not very sure if this works, but try edit your if statement contents with this.
if (AccessCardtextFieldLength == ACCESSCARD_MAXLENGTH){
if (textField == AccessCardTextField) {
textField.resignFirstResponder()
PasswordTextField.becomeFirstResponder()
}
}
In this condition
if (AccessCardtextFieldLength == ACCESSCARD_MAXLENGTH){
PasswordTextField.becomeFirstResponder()
**return true**
}
else{
return true
}
you returning flase that's why it doesn't show your last Character.

Hide keyboard automatically in swift

Is there a way to automatically hide keyboard in swift after inputting four characters? I actually have a code that hides the keyboard but the user has to click anywhere on the screen. Here's the code:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
Thanks in advance!
If I got your question correctly, Consider below example code:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var txtF: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
txtF.delegate = self
txtF.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
}
func textFieldDidChange(textField: UITextField) {
if textField == txtF {
if textField.text?.characters.count == 4 {
self.txtF.resignFirstResponder()
}
}
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField == txtF {
if textField.text?.characters.count > 3 {
self.txtF.resignFirstResponder()
return false
} else {
return true
}
} else {
return true
}
}
}
With above code keyboard will hide when textField have 4 characters and after that if user again tap on textField keyboard will pop up be user will not able to enter any text into textField and keyboard will hide again.
Result will be:
Hope this will help.
Here is the simplest way to hide the keyboard or a numberpad.
First you need a button and you need to make it the size of the screen.Send it to the back of the scene and connect it to an IBAction.Then you code should look like this:
#IBAction func HideKeyboard(sender: AnyObject) {
YourKeyboardHere.resignFirstResponder()
}
This should work for all types of keyboard.
This worked for me:
// Outlet to textfield, editing changed
#IBAction func textFieldEditingChanged(sender: UITextField) {
if sender.text?.characters.count == 4 {
view.endEditing(true)
}
// Optional if you don't want the user to paste in more than 4 characters
else if sender.text?.characters.count > 4 {
sender.text = nil
}
}
I also recommend you setting the
textField.clearsOnBeginEditing = true
so the textField gets cleared when the user clicks on it again.
You should use textfield delegate shouldChangeCharactersInRange something like,
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if (textField.text.length == 4) {
[textField resignFirstResponder];
}
return YES;
}
In Swift,
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField.text?.characters.count == 4 {
textField.resignFirstResponder()
}
return true
}
Hope this will help :)

Limiting characters on UITextField breaks Emojis, can only add one and not delete

I'm using the following code to limit the amount of characters that can be in a UITextField
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let currentCharacterCount = textField.text?.characters.count ?? 0
if (range.length + range.location > currentCharacterCount){
return false
}
let newLength = currentCharacterCount + string.characters.count - range.length
return newLength <= 44
}
This is done by setting the UITextField's delegate to self.
--
The issue here is that if you add an Emoji to the textfield, you cannot remove it. Even if you highlight - select all, or use "cut" the text will not change. The emoji can be before or after text, or even alone in the text field. You also cannot add two emojis to the field.
I don't see what the issue is here, can anyone help me out?
Its better if you don't do any checks inside shouldChange.. function and instead track the length separately using the UITextFieldTextDidChangeNotification notification. Sample code is attached below. In the shouldChange..just return a bool which is set in textDidChange. Here you will get the correct length. I noticed that in your method once you add an emoji it wont even allow you to type anymore. The shouldChangeCharactersInRange is not even getting called after entering a emoji char.
class ViewController: UIViewController, UITextFieldDelegate{
#IBOutlet weak var textField:UITextField!
var allow = true
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "textFieldDidChange:", name: UITextFieldTextDidChangeNotification, object: textField)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return allow
}
func textFieldDidChange(notification:NSNotification)
{
let length = textField.text?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
if length > 44 {
allow = false
} else {
allow = true
}
}
}
In Swift 3.1
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentCharacterCount = textField.text?.characters.count ?? 0
let limit = 10
return currentCharacterCount < limit || string.characters.count < range.length
}
This won't prevent copy and paste long text string, I disabled the paste function for UITextField, with codes from
https://stackoverflow.com/a/39015132/6311644

Resources