问题
I have taken 3 text fields and want them to hold just one integer for OTP purpose (It's the need of the project design). When user enters number in first textfield, the responder should automatically get assigned to the second text field and then to the third text field. As soon as user enters last OTP digit in the third textfield, I want to hit the webservice. What I did so far is :
class ActivationCodeVC: UIViewController, UITextFieldDelegate
then
otpField1.delegate = self
otpField2.delegate = self
otpField3.delegate = self
then
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let text=textField.text
let counter = text?.characters.count
if counter >= 1 {
if textField == otpField1{
otpField2.becomeFirstResponder()
} else if textField == otpField2{
otpField3.becomeFirstResponder()
} else if textField == otpField3{
otpField3.resignFirstResponder()
}
}
return true
}
Cursor should start blinking on the 2nd textfield when user enters digit in the 1st textfield. But it doesn't. After I press the second digit, it enters it to the second textfield and then again cursor doesn't moves to the third, but remains in the second text field. Secondly, when I try to remove digit by backspace, say for, when I try removing 1st textfield digit, it removes digit from the second textfield.
Please help me what methods I should implement and how to achieve the functionality correctly.
I tried this but character is printing in the second text field instead of first and so on.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let text = textField.text
// create Range<Index> object from old-style one
let start = text!.startIndex.advancedBy(range.location)
let end = start.advancedBy(range.length)
let indexRange = start..<end
// calculate result string value
let result = text!.stringByReplacingCharactersInRange(indexRange, withString: string)
// let text=textField.text
let tempCount = result.characters.count
if tempCount == 1 {
if textField == otpField1{
otpField2.becomeFirstResponder()
} else if textField == otpField2{
otpField3.becomeFirstResponder()
} else if textField == otpField3{
otpField3.resignFirstResponder()
let tempCode = otpField1.text! + otpField2.text! + otpField3.text!
if !APPDELEGATE.internetStatusFalse {
KVNProgress.showWithStatus("Loading...")
let soapApiObj: SoapApi = SoapApi()
mode = ControllerTypeMode.ACTIVAITONCODE
soapApiObj.resDelegate = self
soapApiObj.responseString = NSMutableString(string: "")
soapApiObj.callActivationCodeApi(tempCode)
}
else{
let obj: SuccessFullPopVC=self.storyboard?.instantiateViewControllerWithIdentifier("successFullPopVC") as! SuccessFullPopVC
obj.titlelbl = LocalizationSystem.sharedLocalSystem().localizedStringForKey("Warning", value: nil)
obj.imgSuccess = UIImage(named: "warning")
obj.messagelbl = LocalizationSystem.sharedLocalSystem().localizedStringForKey("No internet connection.", value: nil)
self.navigationController?.presentViewController(obj, animated: false, completion: nil)
}
}
}
return true
}
Thanks for the final solution:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let text = textField.text
// create Range<Index> object from old-style one
let start = text!.startIndex.advancedBy(range.location)
let end = start.advancedBy(range.length)
let indexRange = start..<end
// calculate result string value
let result = text!.stringByReplacingCharactersInRange(indexRange, withString: string)
let newLength = result.characters.count
if textField == otpField1{
if newLength == 1 {
otpField1.text = result
otpField2.becomeFirstResponder()
return false
}
} else if textField == otpField2{
if newLength == 1 {
otpField2.text = result
otpField3.becomeFirstResponder()
return false
}
} else if textField == otpField3{
if newLength == 1 {
otpField3.text = result
return false
}
}
return !(result.characters.count>1)
}
It Works!!
回答1:
The shouldChangeCharactersInRange
-delegate method get called before the actual text change (character put/delete in your case).
Firstly, calculate string you'll obtain after the input action. Use delegate method arguments (range
, string
) and textField.text
like in a snippet below.
let text = textField.text
// create Range<Index> object from old-style one
let start = text.startIndex.advancedBy(range.location)
let end = start.advancedBy(range.length)
let indexRange = start..<end
// calculate result string value
let result = text.stringByReplacingCharactersInRange(indexRange, withString: string)
回答2:
Updated for Swift 3:
Used below simple code:
//To asssing next responder
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if (textField == self.nameTextField) {
self.textField = self.emailTextField
self.emailTextField.becomeFirstResponder()
} else if (textField == self.emailTextField) {
self.textField = self.phoneNumberTextfield
self.phoneNumberTextfield.becomeFirstResponder()
} else if(textField == self.phoneNumberTextfield) {
self.textField = self.amountTextField
self.amountTextField.becomeFirstResponder()
} else if (textField == self.amountTextField) {
self.textField = self.descriptionTextField
self.descriptionTextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return false
}
来源:https://stackoverflow.com/questions/38610286/auto-resign-and-assign-first-responder-in-text-field-in-swift