UITextfield letting only one decimal - swift

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.

Related

Swift UITextField .oneTimeCode Autofill does not work

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.

Swift add target for paste action UITextField

I have a UITextField that has a target added which performs checks on the field as the user is typing. I currently have an issue however when my code adds text to the textfield in that the text doesn't get checked. Is there a way I can solve this through .editingChanged or is there another UIControlEvent to hook into?
Code is:
NumberOutlet.addTarget(self, action: #selector(handleNumberImage), for: .editingChanged)
The way you can handle this is by implementing the UITextViewDelegate protocol in your viewcontroller. In your viewDidLoad you would want to set the delegate of your UITextField to self.
Then, simply implement the following method, like demonstrated here:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.length > 1 {
// Text was pasted into the text field
// do something with pasted text
} else {
//typed string
}
return true
}
You will want to conform to the UITextFieldDelegate protocol.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let isAddingCharacter: Bool = range.location >= 0 && range.length == 0
let isDeletingCharacter: Bool = range.location >= 0 && range.length == 1
var newCount: Int = textView.text.characters.count
if isAddingCharacter {
newCount += 1
} else if isDeletingCharacter {
newCount -= 1
}
// If the newCount is > 0, the user is entering text
return true
}
Side note, your outlet should be named numberOutlet, not NumberOutlet. It is convention to use camel case syntax for variable names in swift.
The only way I know would be just to call the method you used as selector after you add text via code.
For example you have a method which is executed after you press a button and there you add text to your textfield and the UIControlEvent doesn't get fired here. So just call the method after adding text via code in this example after pressing a button:
#IBAction func buttonPressed(_ sender: UIButton) {
// Note: camel case convention
numberOutlet.text?.append("added text via code")
// perform your check method
handleNumberImage()
}

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.

Detecting if the user is typing?

For a UITextField, what is the best way to detect if the user is typing and the textfield has a value?
I've tried the following unsuccessfully:
Value Changed: no response
Editing Did End: no response
Touch Up Inside: doesn't trigger until after the user clicks out of the textfield
Try using the shouldChangeCharactersInRange event.
func textField(textField: UITextField,
shouldChangeCharactersInRange range: NSRange,
replacementString string: String)
-> Bool {
// Put your code here
}
This is called whenever a user adds or removes a new character to your UITextField.
If you want to accept the change, return true. Otherwise return false.
Just make sure your UITextField conforms to the UITextFieldDelegate Protocol

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