Swift format text field when user is typing
Is there a way I can recognise when the user is deleting and bypass the text field check?
The problem is that you've implemented the wrong method. Implement the delegate method textField(_:shouldChangeCharactersIn:replacementString:)
. This allows you distinguish where the text is changing (the second parameter is the range), and what the new text is — in the case of the backspace, replacementString
will be empty.
Format text field as user is typing
You can use this code:
func currencyStringFromNumber(number: Double) -> String {
let formatter = NSNumberFormatter()
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
formatter.currencyCode = NSLocale.currentLocale().displayNameForKey(NSLocaleCurrencySymbol, value: NSLocaleCurrencyCode)
return formatter.stringFromNumber(number)
}
let currencyString = currencyStringFromNumber(21010)
println("Currency String is: \(currencyString)")
// Will print $21,010.00
Here's a compilable and working example of this information extrapolated to work as you require.
import UIKit
class CurrencyTextFieldExample: UIViewController {
let currencyFormatter = NSNumberFormatter()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let textField = UITextField()
textField.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged)
textField.frame = CGRect(x: 0, y: 40, width: 320, height: 40)
textField.keyboardType = UIKeyboardType.NumberPad
textField.backgroundColor = UIColor.lightGrayColor()
self.view.addSubview(textField)
currencyFormatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
currencyFormatter.currencyCode = NSLocale.currentLocale().displayNameForKey(NSLocaleCurrencySymbol, value: NSLocaleCurrencyCode)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldDidChange(textField: UITextField) {
var text = textField.text.stringByReplacingOccurrencesOfString(currencyFormatter.currencySymbol, withString: "").stringByReplacingOccurrencesOfString(currencyFormatter.groupingSeparator, withString: "").stringByReplacingOccurrencesOfString(currencyFormatter.decimalSeparator, withString: "")
textField.text = currencyFormatter.stringFromNumber((text as NSString).doubleValue / 100.0)
}
}
Let me know if you have questions.
How to apply format while typing UITextField
I don't think it is worthy to save the caret position when entering a credit card number (or login card). Just implement the deleteBackward method and remove the last digit. The user can always retype the numbers from left to right. I would also subclass textfield and create a custom field. So first remove all non digits from the field and then switch the number of digits left. If there is from 3 to 11 just insert the first hyphen. If there is 12 insert the first and second hyphens. If there is 13 add the third hyphen as well. Make sure to insert them in reverse other to make your life easier:
class LoginField: UITextField {
override func didMoveToSuperview() {
keyboardType = .numberPad
textAlignment = .center
autocorrectionType = .no
addTarget(self, action: #selector(editingChanged), for: .editingChanged)
}
override func deleteBackward() {
text?.removeAll(where: \.isDigit.negated)
let _ = text?.popLast()
sendActions(for: .editingChanged)
}
}
extension LoginField {
@objc func editingChanged(_ textField: UITextField) {
text?.removeAll(where: \.isDigit.negated)
text = text?.prefix(15).string
if let offset = text?.count,
let startIndex = text?.startIndex {
switch offset {
case 3...11:
if let index = text?.index(startIndex, offsetBy: 3) {
text?.insert("-", at: index)
}
case 12:
if let index = text?.index(startIndex, offsetBy: 12) {
text?.insert("-", at: index)
}
if let index = text?.index(startIndex, offsetBy: 3) {
text?.insert("-", at: index)
}
case 13...15:
if let index = text?.index(startIndex, offsetBy: 13) {
text?.insert("-", at: index)
}
if let index = text?.index(startIndex, offsetBy: 12) {
text?.insert("-", at: index)
}
if let index = text?.index(startIndex, offsetBy: 3) {
text?.insert("-", at: index)
}
default: break
}
}
}
}
extension Bool {
var negated: Bool { !self }
}
extension LosslessStringConvertible {
var string: String { .init(self) }
}
extension Character {
var isDigit: Bool { "0"..."9" ~= self }
}
How to format a textfield so when user inputs data its in format similar to 80/150?
You could do it this way, after setting self
as the delegate:
let slash = "/"
let digits = CharacterSet(charactersIn: "0123456789")
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//Deleting
if string.count == 0 {
var text = textField.text!
let start = text.startIndex
let beginRange = text.index(start, offsetBy: range.location)
let endRange = text.index(start, offsetBy: range.location + range.length)
text = String(text.prefix(upTo: beginRange))
+ String(text.suffix(from: endRange))
text = text.replacingOccurrences(of: "/", with: "")
if text.count >= 3 {
text = String(text.prefix(2)) + "/" + String(text.dropFirst(2))
}
textField.text = text
return false
}
//Typing
let count = textField.text!.count
guard string.count == 1,
count < 6,
let scalar = Character(string).unicodeScalars.first else {
return false
}
let isDigit = digits.contains(scalar)
switch count {
case 0, 3..<6 :
return isDigit
case 1:
if isDigit {
textField.text = textField.text! + string + "/"
}
return false
case 2:
if string == slash {
return true
} else {
textField.text = textField.text! + "/" + string
return false
}
default:
return false
}
}
This code works with the default keyboard too, and not just the numeric pad.
Add default text in textfield with follow of user typing value
Use this UITextField subclass, configure your postfix, and enjoy
improved
class PostFixTextField: UITextField {
@IBInspectable var postfix : String = ""
@IBInspectable var removePostfixOnEditing : Bool = true
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.addTarget(self, action: #selector(textHasChanged), for: .editingDidEnd)
self.addTarget(self, action: #selector(removePostFix), for: .editingDidBegin)
self.addTarget(self, action: #selector(textHasChanged), for: .editingChanged)
}
func textHasChanged()
{
self.removePostFix()
self.addPostFix()
self.setCursorPosition(input: self, position: (self.originalText()?.characters.count)!)
}
private func setCursorPosition(input: UITextField, position: Int) {
let position = input.position(from: input.beginningOfDocument, offset: position)!
input.selectedTextRange = input.textRange(from: position, to: position)
}
func addPostFix()
{
if(self.text != nil)
{
self.text = self.text! + postfix
}
}
func originalText() ->String?{
let prefixRange = NSString(string: (self.attributedText?.string)!).range(of: postfix)
if(prefixRange.location != NSNotFound)
{
return self.text!.replacingOccurrences(of: postfix, with: "")
}
return self.text
}
func removePostFix(){
if(self.removePostfixOnEditing && self.text != nil)
{
self.text = self.originalText()
}
}
}
Hope this helps you
Append text to textfield while typing
First you need to import UITextFieldDelegate.
class myClass: UITextFieldDelegate
Then in viewDidload delegate your UITextFeild
textField.delegate = self //PUT the name of your textField
Then add this code also
textField.addTarget(self, action: "textFieldChanged:", forControlEvents: UIControlEvents.EditingChanged)
Then call this function
func textFieldChanged(textField: UITextField) {
if textfield.text != "" {
textfield.text = "\(self.enteredNumber) + LBS"
}
}
How do I format UITextField text in real time, while it's being edited?
Add a "textFieldDidChange" notification method to the text field control.
[textField addTarget:self
action:@selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
-(void)textFieldDidChange:(UITextField *)theTextField
{
NSLog(@"text changed: %@", theTextField.text);
NSString *textFieldText = [theTextField.text stringByReplacingOccurrencesOfString:@"," withString:@""];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSString *formattedOutput = [formatter stringFromNumber:[NSNumber numberWithInt:[textFieldText integerValue]]];
textField.text=formattedOutput;
}
Related Topics
How to Display Mtkview with Rgba16Float Mtlpixelformat
Swift Cannot Output When Using Nstimer
Stopping Timer at Defined Amount of Time in Swift
Code Only Retrieving One Value from Data in Firebase
How to Move a Model and Generate Its Collision Shape at the Same Time
Error: Argument Type Double/String etc. Does Not Conform to Expected Type "Anyobject"
Example for Drag and Drop Inside Nscollectionview
Ibeacon: Get Advertisement Package Faster
Update Text in While Loop Swift
Array Search Function Not Working in Swift
How to Run the Simulator the Operation Couldn't Be Completed. (Launchserviceserror Error 0.)
Switch Statement for Imported Ns_Options (Rawoptionsettype) in Swift
Declaring Conformance to @Objc Protocol in Empty Extension Breaks with Exc_Bad_Instruction
Swift Why Isn't My Date Object That's (Equatable) Equal After Converting It to a String and Back
Can the Byte Order of Double Be Safely Reversed
Why Can't I Use 'Type' as the Name of an Enum Embedded in a Struct
Get Images from Document Directory Not File Path Swift 3
Behavior of the Cameranode Is Unclear When Moving a 3D Model in a Scene with Scenekit