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.
Related
How could I detect if user clicked on comma or decimal numpad, so if a textfield is empty and the user clicked on comma or dot decimal separator on a decimal numpad I would like to append textfield text with "0,"? I know that I could use uitapgesture on the whole textfield, but that's not what I need.
override func viewDidLoad() {
super.viewDidLoad()
yourTextFiled.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (string == "." || string == ",") && textField.text?.count == 0{
textField.text = "0"
}
return true
}
you can try Like Below Also
override func viewDidLoad() {
super.viewDidLoad()
yourTextField.addTarget(self, action: #selector(functionName), for: .editingChanged)
}
#objc func functionName(){
guard let textFieldValue = yourTextField.text else {return}
if yourTextField.count != 0 && (yourTextField == "," || yourTextField == "."){
yourTextField.text = "0"
}
}
I have 2 textFields with NumberPad keyboard type
#IBOutlet weak var ourTextField: UITextField!
#IBOutlet weak var forThemTextField: UITextField!
and I want to automatically move to the other textfield (from ourTextField to forThemTextField) after entering two numbers inside the ourTextField then after going to the other textfield (forThemTextField) and entering 2 numbers I want the keyboard hide automatically
I have added a condition to only accept two numbers in my textFields by this code :
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let lengthsDictionary = [ourTextField : 2, forThemTextField: 2]
guard let length = lengthsDictionary[textField] else {
return true
}
let currentCharacterCount = textField.text?.count ?? 0
if (range.length + range.location > currentCharacterCount){
return false
}
let newLength = currentCharacterCount + string.count - range.length
return newLength <= length
}
Use shouldChangeCharactersIn of UITextFieldDelegate method & listen with keyboard string
Use tag of textFields, like tag 1 & tag 2
as
class TestingViewController: UIViewController{
#IBOutlet weak var firstTextField: UITextField!
#IBOutlet weak var secondTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
firstTextField.delegate = self
secondTextField.delegate = self
firstTextField.tag = 1
secondTextField.tag = 2
firstTextField.keyboardType = .numberPad
secondTextField.keyboardType = .numberPad
}
}
extension TestingViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return textField.shouldChangeCustomOtp(textField: textField, string: string)
}
}
extension UITextField {
func shouldChangeCustomOtp(textField:UITextField, string: String) ->Bool {
//Check if textField has two chacraters
if ((textField.text?.count)! == 1 && string.count > 0) {
let nextTag = textField.tag + 1;
// get next responder
var nextResponder = textField.superview?.viewWithTag(nextTag);
if (nextResponder == nil) {
nextResponder = textField.superview?.viewWithTag(1);
}
textField.text = textField.text! + string;
//write here your last textfield tag
if textField.tag == 2 {
//Dissmiss keyboard on last entry
textField.resignFirstResponder()
}
else {
///Appear keyboard
nextResponder?.becomeFirstResponder();
}
return false;
} else if ((textField.text?.count)! == 1 && string.count == 0) {// on deleteing value from Textfield
let previousTag = textField.tag - 1;
// get prev responder
var previousResponder = textField.superview?.viewWithTag(previousTag);
if (previousResponder == nil) {
previousResponder = textField.superview?.viewWithTag(1);
}
textField.text = "";
previousResponder?.becomeFirstResponder();
return false
}
return true
}
}
Output:
In viewDidLoad :-
ourTextField?.addTarget(self, action: #selector(CalculatorViewController.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
forThemTextField?.addTarget(self, action: #selector(CalculatorViewController.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
//create function
func textFieldDidChange(_ textField: UITextField) {
if textField == ourTextField {
if (textField.text.count)! >= 2 {
forThemTextField?.becomeFirstResponder()
}
}
else if textField == forThemTextField {
if (textField.text?.count)! >= 2 {
forThemTextField.resignFirstResponder()
}
}
}
Add target to the UITextField (in viewDidLoad()), for example:
mTfActuallyFrom?.addTarget(self, action: #selector(CalculatorViewController.textFieldDidChange(_:)), for: UIControlEvents.editingChanged)
In the delegate function, use UITextField.becomeFirstResponder() to move the focus to the next textfield. Change your conditions to your requirement. For example:
func textFieldDidChange(_ textField: UITextField) {
if textField == mTfActuallyFrom {
if (textField.text?.characters.count)! >= 4 {
mTfActuallyTo?.becomeFirstResponder()
}
}
else if textField == mTfActuallyTo {
if (textField.text?.characters.count)! >= 4 {
dismissKeyboard(gesture: nil)
}
}
}
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!
I want to perform some action when my textField character count becomes 6 in swift.
Use the delegate
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
and then implement
func textFieldDidChange(_ textField: UITextField) {
if textField.text?.characters.count == 6 {
// Call some method
}
}
You can use shouldChangeCharactersInRange to get length as well as position using range.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = (textField.text ?? "") as String
let txtAfterUpdate = text.replacingCharacters(in: range, with: string)
if (text.characters.count == 6 && range.location > 5) {
return false // if you want to restrict your string length of call some method here
}
return true
}
I have 4 UITextFields in one UIView like this:
each UITextField limited to 4 characters. i want implement a auto switching between UITextFields with count characters of each UITextField.
i use shouldChangeCharactersIn for limitation characters:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let maxLength = 4
var newString = String()
let currentString: NSString = textField.text! as NSString
newString = currentString.replacingCharacters(in: range, with: string)
return newString.length <= maxLength
}
and this is my switching implement:
func textFieldDidChange(_ textField: UITextField){
let text = textField.text
if text?.utf16.count == 4 {
switch textField {
case firstPartTextField:
secondPartTextField.becomeFirstResponder()
case secondPartTextField:
thirdPartTextField.becomeFirstResponder()
case thirdPartTextField:
fourthPartTextField.becomeFirstResponder()
default:
break
}
}
}
my problem is switch to previous UITextField in deleting texts, i can not detect backSpace event when UITextField is empty.
Add target for textField in viewDidLoad()
firstTxt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
secTxt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
thirdTxt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
fourTXt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
Than create selector method
func textFieldDidChange(textField: UITextField){
let text = textField.text
if text?.utf16.count == 1{
switch textField{
case firstTxt:
secTxt.becomeFirstResponder()
case secTxt:
thirdTxt.becomeFirstResponder()
case thirdTxt:
fourTXt.becomeFirstResponder()
case fourTXt:
fourTXt.resignFirstResponder()
default:
break
}
}else{
}
}
Make an outlet collection of all your textfields and configure them like so:
OutletCollection:
#IBOutlet var textfields: [UITextField]!
Add this in viewDidLoad:
for (i, tf) in textfields.enumerated() {
tf.layer.cornerRadius = 5
tf.clipsToBounds = true
tf.tag = i
tf.delegate = self
}
In the target function, you'll restrict the count in this manner:
func textFieldDidChange(textField: UITextField) {
let text = textField.text!
if text.utf16.count >= 4 {
if textField.tag < 4 {
codeTextfields[textField.tag + 1].becomeFirstResponder()
}
else {
textField.resignFirstResponder()
}
}
}
This will the change in one of your delegate methods:
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.text = ""
}
Refined version of the following answer: How to move cursor from one text field to another automatically in swift ios programmatically?