Swift UITextField .oneTimeCode Autofill does not work - swift

I'm trying to implement the one time code functionality for a sms code on iOS.
The number code e.g "8737" shows up right above the keyboard, from the Message we send e.g "Code: 8737", but when tapping the code it is not automatically inserted in the textfield.
I created a simple textfield without any customisation except
textField = UITextField()
if #available(iOS 12.0, *) {
textField.keyboardType = .default
textField.textContentType = .oneTimeCode
textField.delegate = self
} else {
// Fallback on earlier versions
}
And I implemented the delegate
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return true
}
Its the only textfield on the ViewController and directly added to its view and i called becomeFirstResponder when it appears.
Question one:
Is there a way to use codes mixed with numbers and letters like "AB837" ? I have tried all the phrases like "Passcode: ****" and "Code: ****" but neither is working when letters are added.
Question two:
What can be done wrong, that autofill to the textfield does not work?
I tap the code which is shown above the keyboard and the delegate method is called as well, but the code is not available in any variable of the delegates method or in the clipboard.

Related

How to hide the last digit while writing a password in swift

Recently I've been working on a UITextField that hides the password while editing text on the loginPage, password field.
As everyone knows .isSecureTextEntry = true solves the problem up to a point. However, while typing the password, the last character appears and is perceived as a security hole in a way. So I could not find out a solution how to solve this. Thank you in advance for your answers.
I attached two pictures.
The solution offered by UIKIT today.
textField.isSecureTextEntry = true
It's what I wanted.
I want this
When ever you input the character the func textField(_:shouldChangeCharactersIn:replacementString:) will call to replace old text with new text. So you just need to catch the value and don't let it update by default.
textField.isSecureTextEntry = true
textField.delegate = self // add delegate to catch the action
Get the value when changing in your TextField and don't get it update the UI automatically.
extension ViewController : UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let currentText = self.textField.text as? NSString {
let newText = currentText.replacingCharacters(in: range, with: string) // change to new one
self.textField.text = newText // assign it back to textField text
return false // don't let it update automically
}
return true // by default
}
}
If you have multiple textField in the screen you must checked if the current changing is your password one before. If yes return false else return true like default.

UITextField shouldChangeCharacters in swift is not working for the first letter entered

I have a textfield population phone number. When i am entering phone number i am checking validation for a invalid phone number. i am using delegate method "textfield should change characters".It is working fine but it is not working for the first letter entered by the user.
extension phoneCell: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
validateInput(of: textField)
return true
}
Can any one help me to resolve this?
If you noticed then shouldChangeCharactersIn has a return type Bool.
What it means is that when a user presses a key on the keyboard, you'll get a callback by this delegate before even registering that character in the textfield.
Now if you return true, that pressed character will be reflected in the textfield if you return false, input will be discarded.
So for first time your string.count will be 1 but your textfeild.text.count will be 0.
Looking at your validation code I will suggest you add an IBAction on your textfeild for editing changed[here].
What does your validation function do? Why are you returning true by default?
shouldChangeCharactersIn should return the result of your validation function.

UITextfield letting only one decimal

How to let user insert only one decimal in the textfield in language Swift.There are quite a lot of help for this on the site,but none of them work as they are all Swift 1 code. Thank you in advance.
First, you should make your class conform the to the UITextFieldDelegate protocol like this:
class YourViewController: UIViewController, UITextFieldDelegate
Then, you should set the delegate of your textField to self:
yourTextField.delegate = self
Finally, whenever the content of your UITextField changes, this delegate method will be called, so add it to your view controller.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
//handle changes here
}
If you want only one character to appear you could disallow changes to the content of your UITextField when it is already filled:
if yourTextField.text?.characters.count > 0 {
return false
}
return true
If you only want to allow decimal characters you could check for this too, and add the condition to the if query.

Making it so the user cannot press the button unless something is entered in the textfield

How would I make it so a button that uses the segue to send you to the next view controller not work if nothing is entered in the text field above it?
Add this to the viewdidload, replacing textfieldVerb with the name of your textbox, and nextVerbOutlet with the name of your button (as a outlet)
self.textFieldVerb.addTarget(self, action: "textFieldChanged:", forControlEvents: .EditingChanged)
self.textFieldVerb.addTarget(self, action: "textFieldChanged:", forControlEvents: .EditingChanged)
nextVerbOutlet.enabled = false
and then add this replacing textfieldVerb with the name of your textbox, and nextVerbOutlet with the name of your button (as a outlet). This doesn't go in the viewdidload, but under it.
func textFieldChanged(sender: UITextField) {
// simple validation
if textFieldVerb.text?.characters.count > 0
&& textFieldVerb.text?.characters.count > 0 {
self.nextVerbOutlet.enabled = true // re-enable your button
}
}
You could implement optional func textField(_ textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool of the UITextFieldDelegate. It will get triggered every time user enters or deletes character in the text field. You can examine the contents there and enable/disable your button from there appropriately.
You could check for the content of the TextField:
if myTF.text != "" || myTF.text != nil {
//TextField contains something
//enable button
//segue to next ViewController
} else {
//TextField empty
//disable button
}
If you implement that into textFieldDidEndEditing() it will check each time the user is done typing.
Make sure to include the UITextFieldDelegate in your class like:
class myClass: UIViewController, UITextFieldDelegate {...}
Hope that helps :)
Implement the UITextFieldDelegate protocol and set your VC as the delegate.
Then implement the
func textField(_ textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String)
method of that protocol.
You use this method to detect an empty string. You can choose to be thorough and handle copy/paste in which case you will need to calculate the value of the new string after the replacement using stringByReplacingCharactersInRange, or you can choose to not handle copy paste and just check that range.location > 0.
Based upon the the above you can set the enabled property of the button accordingly.

UITextView paste method override

I really want to be able to detect a paste event in a UITextView, however it appears this cannot be done.
I originally tried subclassing a UITextView and overriding the paste: method, but it never gets called on a paste event.
Has anyone been able to do this? A previous question on the same ilk didn't have an answer back in August...
The text view doesn't catch the paste: event because it wasn't the actual responder is not the text view, but the private web view (UIWebDocumentView) that powers the text view.
However, on paste, the web view will call the text view's (private) -[UITextView keyboardInput:shouldInsertText:isMarkedText:], and in turn, the text view's delegate's -textView:shouldChangeTextInRange:replacementText:.
Therefore, you just need to implement -textView:shouldChangeTextInRange:replacementText: in the text view's delegate.
(Of course, normal keyboard input will trigger this method too. There's no perfect way to distinguish them.)
#KennyTM what I did for one of my applications was keep up with the current text length and the previous text length. If the (currentTextLength - previousTextLength) was greater than 1, then the user must have pasted something
With iOS 14 you have to do this in two parts to avoid showing the user notification that you are checking the UIPasteboard. In my case I did not want to do anything bad with the user data but I did want to do some special formating when the user did paste into the UITextView.
Step 1: Create a custom UITextView and override paste()
import UIKit
protocol TouchableTextViewDelegate : class{
func touchesDidBegin()
func pasting()
}
class TouchableTextView: UITextView {
weak var touchableDelegate : TouchableTextViewDelegate?
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if self.isFirstResponder{
return true
}
touchableDelegate?.touchesDidBegin()
return false
}
override func paste(_ sender: Any?) {
touchableDelegate?.pasting()
super.paste(sender)
}
}
Step 2: In the file location where you handle the shouldChangeTextIn create a variable and be sure to set the delegate for the TouchableTextView. In my case
//top of the view
var isPasting : Bool = false
//also when creating UITextView use both delegates
textView.touchableDelegate = self
//add the normal delegate
textView.delegate = self
extension SliderTextView : TouchableTextViewDelegate{
func pasting() {
self.isPaste = true
}
func touchesDidBegin() {
sliderEditingDelegate?.touchesDidBegin(sliderTextView: self)
}
}
Step 3: Inside shouldChangeTextIn I handle the action like this
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let isPaste = self.isPaste
//be sure to set this to false
self.isPaste = false
if isPaste,
let pt = UIPasteboard.general.string,
text.contains(pt){
//you will see the paste notification and that is good for the user
// but only when the user pastes
// do whatever special thing or formatting you want to do
}
return true
}
The good is that you will not trigger the notification unless the user is pasting in the UITextView.
To detect if a user is parsing a text in a textView, compare the replacementText in the shouldChangeTextInRange delegate with the text the user is currently holding in the UIPasteboard. Then take action depending on requirements.
for code, see my answer in the following question:
how to know when text is pasted into UITextView