I have a UItextField called textField on a static cell tableView. That field contains a currency amount - like "$10,000.00".
When editing that amount, the currency and thousand grouping symbols are a bit in the way. Therefore I would like to remove those when the field becomes the first responder.
I do this in textFieldShouldBeginEditing.
The first time I do this, everything works. The textField's contents are reformatted without currency and thousand group separator.
On textFieldDidEndEditing I re-format the value into a proper currency string again. This also works.
The problem happens when I re-enter the field for a 2nd time. While debugging I can see the textField.text has changed into the string without currency symbol and grouping symbol, but the display does not show that. Although it did work the first time! The 2nd time it looks like there is a mismatch between what is on the screen and what value the debugger sees.
I've tried things like:
tableView.beginUpdates(); tableView.endUpdates()
textView.setNeedsDisplay
... but this does not work.
So I copied the code that removes the currency formatting in textFieldShouldBeginEditing to a new delegate method textFieldDidBeginEditing.
Then everything worked fine. I could tap other controls and back to the textField a number of times and each time the control would lose its formatting when entered and would be restored to a formatted currency string after losing focus.
So I decided to delete the method textFieldShouldBeginEditing. But then things broke down again! It looks like I have to implement both textFieldShouldBeginEditing as well as textFieldDidBeginEditing to be able to prepare a textField's contents for user-editing?
Is this a bug?
extension Double {
public func doubleToString(numberStyle: NumberFormatter.Style, decimals: Int, withThousandSeparator: Bool) -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = numberStyle
numberFormatter.maximumFractionDigits = decimals
if !withThousandSeparator {
numberFormatter.groupingSeparator = ""
}
return numberFormatter.string(from: NSNumber(value: self)) ?? ""
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField === self.textField {
textField.text = amount.doubleToString(numberStyle: .decimal, decimals: 2, withThousandSeparator: false)
}
}
You should try textField's text changed event, attaching code below :
Add target on textField for text changed :
self.textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
Function for textField's text change :
func textFieldDidChange(_ textField: UITextField)
{
if textField === self.textField
{
//try formatting here
}
}
Related
I have a UITextField with date picker, and I want to use the default built in button to clear the text field, it doesn't seems to work.
I tried overriding
func textFieldShouldClear(_ textField: UITextField) -> Bool {
searchBar.text = "" //my textfield is called searchBar and I tried to clear the text like that
return true
}
It seems that the method is called and printing the textfield says its empty but its not and in the view shows the last date I entered. Any ideas? Thanks in advance.
You are searching this:
textfield.clearButtonMode
Have you tried to replace searchBar with textField (local variable) in the function like this?
func textFieldShouldClear(_ textField: UITextField) -> Bool {
textField.text = "" // use local variable textfield here
return true
}
I found out that clear button is updating the text field and still takes the date from the date picker... Now I am trying to clear the value of the date picker maybe this will work.
I have a UITextField that holds the text: "Username". I want to erase the user name once the user has selected the text field for editing.
Is there a better way than using the selector method?
Here is the method I'm currently using, but it doesn't seem to be working.
usernameTextField.addTarget(self, action: #selector(selectedUsernameField), for: .editingChanged)
func selectedUsernameField(sender: UITextField){
print("selectedUsernameField")
usernameTextField.text = ""
}
I this case you should set the placeholder for usernameTextField.
usernameTextField.placeholder = "UserName"
It will disappear as user will start typing that's what you want.
You can use this function:
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == usernameTextField{
textField.text = ""
}
}
It is called when the text field begins editing.
Although to use it you will need to make your class a UITextFieldDelegate
and also say:
usernameTextField.delegate = self
in viewDidLoad.
Requirement
I want to block a text field (UITextField) while another text is being entered in another text field.
Example
I have two text fields on a form. When typing in the first text field, the second text field is disabled (i.e. you can not even press it by touching), only when you finish editing the first text field, you can edit the second one.
You can add your textfield to an an array and use the Equatable protocol to compare the textfield in the DidBeginEditing func and "disable" other fields. But when you are done editing you need to turn all your textfields back on. Also make sure your class has UITextFieldDelegate in the declaration.
var textfields: [UITextField] = [textfield1,textfield2,textfieldn]
func textFieldDidBeginEditing(textField: UITextField) {
for field in textfields {
if textField != field {
field.enabled = false
}
}
}
func textFieldDidEndEditing(textField: UITextField) {
for field in textfields {
field.enabled = true
}
}
I have an UITextField which user sets its luggage weight as numbers in TextField. I want to set that textfields value with weight mark (for ex 10 KG which comes from user settings) so whatever user types, there will be KG mark at the end of its textfield. Is there any way for it?
do like
initially clear the value when begin start
func textFieldShouldBeginEditing(textField: UITextField) {
textField.text = ""
}
when editing is over append the kg
func textFieldDidEndEditing(textField: UITextField) {
yourTextfieldName.text = "\(textField.text!) KG"
}
Choice-2
func textFieldDidEndEditing(textField: UITextField)
{
if !textField.text!.rangeOfString("KG").location != NSNotFound {
self.textField.text = textField.text!.stringByAppendingString("KG")
}
}
You could place a "Label" next to the UITextField.
And then just change the text of the Label to whatever the user selects.
OR (but i dont know if that works), try to get the text form the textfield, add the unit (as a string) to the string from the textfield.
I have a UITextField associated with a PickerView (the PickerView is the inputView of the textField)
Il works fine, but I would like to disallow editing in my TextField (not be able to select, copy text, to see the insertion point, ...).
I red here to implement textField shouldChangeCharactersInRange, for the delegate of the uITextField, but it doesn't work...
The method is never called, but the delegate is correctly done, because if I implement textFieldShouldBeginEditing, it is called.
Is there any (simple) way to do what I want?
give your UITextField id and then implement textFieldShouldBeginEditing delegate. Inside those delegate, check the textField id, if it matches your desired textField, run function to called your picker view and return false in textFieldShouldBeginEditing delegate.
The following disallows pasting and cutting text unless the result is exactly the result from the picker. For example purposes I'm assuming this is a UIDatePicker.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
return string == formatter.stringFromDate(datePickerView.date)
}
where formatter is something like
let formatter = NSDateFormatter()
formatter.locale = NSLocale.currentLocale()
formatter.dateFormat = "dd/MM/yyyy"
Additionally, if you programmatically set the textfield to a string date, you may want to synchronize the inputView picker of the textField with
func textFieldShouldBeginEditing(textField: UITextField) -> Bool
{
if let text = textField.text {
if let date = formatter.dateFromString(text) {
datePickerView.setDate(date, animated: true)
}
}
return true
}