Force patterns in textfields - swift

(Swift)
So the problem is:
My app (which is a kind of calculator) is crashing when the user puts in the textfield things that can't be calculated.
For example, if he types " -4-.", the app won't be able to do the math.
So, a pattern must be followed.
The following characters are allowed: 1234567890.-
The minus sign can only be typed when it is the first character in the textfield and cannot be typed again.
The point can only be typed after a number, and cannot be typed again.

Well you would have to determine:
When the user clicks on a number/digit/character, you would have to do a:
//Goes at top of one of your classes
var decimalCount:Int = 0
//At location of tap for character
if(decimalCount < 1) {
textField.text += "."
decimalCount += 1
}
This ideology could be applied to "-" as well.

Some how i have understood your question. According to my assumption our task is to validate the input for proper math function.Ok here we go.
First of all declare a bool variable at top of your class
var isNonNumericCharactersAllowes = true
At first we need to make our textfield to respond according to user input.So add delegate to text field and add the following delegate method.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
//1. To make sure that this is applicable to only particular textfield add tag.
if textField.tag == 1 {
let char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
let isBackSpace = strcmp(char, "\\b")
//Helps to react only while typing and not while clearing text
if (isBackSpace != -92) {
let numbersOnly = NSCharacterSet(charactersInString: "1234567890")
let characterSetFromTextField = NSCharacterSet(charactersInString: string)
let Validate:Bool = numbersOnly .isSupersetOfSet(characterSetFromTextField)
if !Validate {
if isNonNumericCharactersAllowes {
isNonNumericCharactersAllowes = false
return true
}
return false
}
isNonNumericCharactersAllowes = true
}
}
return true
}
The above method stops unusual text entry's such as 0..012,--4,4++ etc..
Now while hitting calculate button we need to some validation.Add the following code in IBAction.
#IBAction func calculate(sender: AnyObject) {
let textContent:String!
textContent = textFieldTwo.text
var characterContainer = textContent.characters.map { String($0) }
let numbersOnly = NSCharacterSet(charactersInString: "1234567890")
let lastObjectOfString = NSCharacterSet(charactersInString: characterContainer.last!)
let Validate:Bool = numbersOnly .isSupersetOfSet(lastObjectOfString)
if !Validate {
characterContainer .removeLast()
textFieldTwo.text = characterContainer .joinWithSeparator("")
}
}
This above validation helps in removing things like 30+20+,4+4+, etc.. i.e removes unused operators at the end.

Related

Custom keyboard and shouldChangeCharactersIn

I have custom keyboard which I added as textfield.inputView. But my shouldChangeCharactersIn at UITextFieldDelegate doesn’t work? Any idea?
You have to implement the call to the delegate method yourself prior to inserting the text into the control.
For example, let’s assume you have some function for handling tap of a button, which calls UIKeyInput method insertText. Just check that the delegate implements the method and that it did not return false:
#objc func didTapButton(_ sender: ...) {
guard let range = target?.selectedRange else { return } // assumes `target` was defined to conform to `UITextInput`, using extension shared below
let string = ...
if let textField = target as? UITextField, textField.delegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) == false {
return
}
if let textView = target as? UITextView, textView.delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: string) == false {
return
}
target?.insertText(string) // assumes `target` was defined to conform to `UIKeyInput`
}
Where:
extension UITextInput {
var selectedRange: NSRange? {
guard let textRange = selectedTextRange else { return nil }
let location = offset(from: beginningOfDocument, to: textRange.start)
let length = offset(from: textRange.start, to: textRange.end)
return NSRange(location: location, length: length)
}
}
Clearly, the details are dependent upon your custom keyboard implementation (the above is based upon https://stackoverflow.com/a/57275689/1271826), but hopefully it illustrates the basic idea.

How to use shouldChangeCharactersInRange to continuously format a number

I have a UITextField validate that converts a user's numeric input. For example, if the user types in a 1, it becomes 0.01. If the user types 12, it becomes 0.12.
My code is working correctly when I have the validation code in textFieldDidEndEditing. However, I've been asked to rewrite the code a bit so that the validation occurs as the user is typing as opposed to when they're finished with the textfield, so it makes sense to use shouldChangeCharactersInRange. However, I'm a little confused how to write my code now.
Old code (working):
func textFieldDidEndEditing(_ textField: UITextField) {
if var text = textField.text,
let float = Float(text) {
let formattedFloat = float/100
if let formatterExists = formatter {
text = String.localizedStringWithFormat("\(String(describing: formatterExists))", formattedFloat)
}
let numericString = text.replacingOccurrences(of: ",", with: "")
cellModel.stringInput = numericString
}
}
New code (not working):
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let float = Float(string) {
let formattedFloat = float/100
var text = string
if let formatterExists = formatter {
text = String.localizedStringWithFormat("\(String(describing: formatterExists))", formattedFloat)
}
let numericString = text.replacingOccurrences(of: ",", with: "")
print(numericString)
textField.text = text
cellModel.stringInput = numericString
}
return false
}
I know that in my shouldChangeCharactersInRange code, everytime I type a character, it is taking that character and applying the validation, and only doing it for a single character (as in if I type 1, I get a 0.01, and if I type a 2, the previous character gets replaced and I get a 0.02).
I'm wondering what is a good method for a user to be able to continuously input a number and keep having the validation applied as the user types.
Thanks!

Swift: Add comma and $ in the textfield when typing

I want the users see the $ and comma when they are typing in a textfield from numberPad (Without a decimal dot). Previously I got help and use below codes. But clients will not type the decimal (Only Int value).
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let oldText = textField.text! as NSString
var newText = oldText.stringByReplacingCharactersInRange(range, withString: string) as NSString!
var newTextString = String(newText)
let digits = NSCharacterSet.decimalDigitCharacterSet()
var digitText = ""
for c in newTextString.unicodeScalars {
if digits.longCharacterIsMember(c.value) {
digitText.append(c)
}
}
let formatter = NSNumberFormatter()
// formatter.usesSignificantDigits = false
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
formatter.locale = NSLocale(localeIdentifier: "en_US")
let numberFromField = (NSString(string: digitText).doubleValue) / 100
newText = formatter.stringFromNumber(numberFromField)
textField.text = String(newText)
return false
}
When typing, it always starts from the second decimal unit, How to remove the ".00" via editing the code and let it start from the unit? I tried for a long time, thanks in advance.
First, you got some bad advice. You should not be using shouldChangeCharactersInRange to change the characters in a text field. That's for checking if the characters typed are valid for the field. The only thing you should do in this method is return true if the user entered digits or delete, otherwise false. (Remember, the user may be using an external keyboard so just having the keypad up isn't good enough to stop non-digit entry.)
Instead you should be using an #IBAction connected to the field's EditingChanged event. Inside this method is where you should update the text.
#IBAction func editingChanged(sender: UITextField) {
let digits = sender.text?.digitsOnly ?? "0"
sender.text = "$\(digits).00" // If I understand what you want.
}
The below extension should be somewhere in your code base. It's generally useful so store it in a gist or something, you will likely need it in future projects.
extension String {
var digitsOnly: String {
return componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("")
}
}
You have to make sure that the IBAction is attached to the EditingChanged event:
For Swift 4x
extension String {
var digitsOnly: String {
return components(separatedBy: NSCharacterSet.decimalDigits.inverted).joined(separator: "")
}
}

How to limit text field entry to a certain range of numbers in Swift

enter image description hereI have managed to prevent the user from entering more than 2 digits in the 'month' field, using a text delegate function:
Swift code
However, I also want to prevent the user entering a number greater than 12. Can anyone point me in the right direction?
Thanks!
Add Int(myString) < 13 in your return condition with && operator.
in didload
txt_field.delegate=self
txt_field.addTarget(self, action:"submit:", forControlEvents: UIControlEvents.EditingChanged)
then define "submit" method as
#IBAction func submit(sender: AnyObject) {
let a:Int? = txt_field.text.toInt()
if a > 12{
print("number is greater than 12")
}
else{
print("number is less than 12")
}
}
"submit" method is called each time user stops editing the textfield. Hence you can check what user is entering and prevent him from entering value greater than 12.
Hope it helps.
Happy Coding.
textEdit.delegate = self from your view controllar
extension UserProfileViewController: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let numberFiltered = string.components(separatedBy: NSCharacterSet(charactersIn: "0123456789").inverted).joined(separator: "")
guard string == numberFiltered, range.location < 2 else {
return false
}
if let newValue = textField.text?.intValue, let currentValue = string.intValue {
let totalValue = newValue*10 + currentValue
switch totalValue {
case 16..<80:
return true
default:
textField.text = ""
return false
}
}
return true
} }

Swift - Make defined range of a text field editable

I have a text field and would like to make a part of it editable (not the whole text field).
I tried out something like the code below, to make only the first 6 characters of the text field editable. However, without any success.
#IBOutlet weak var textField: UITextView!
textField.editable(NSRange(location: 0, length: 6)) = true
Does anyone know to solve this issue?
Thanks for your support!
let user enter only 6 char and digits , I have been using this..!!
use this function in your view controller
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
var result = true
let prospectiveText = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if textField == textField {
if count(string) > 0 {
let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
let resultingStringLengthIsLegal = count(prospectiveText) <= 6
let scanner = NSScanner(string: prospectiveText)
let resultingTextIsNumeric = scanner.scanDecimal(nil) && scanner.atEnd
result = replacementStringIsLegal &&
resultingStringLengthIsLegal &&
resultingTextIsNumeric
}
}
return result
}
and put this in viewDidAppear
textField.delegate = self
and inherit
class YourClassName: UIViewController, UITextFieldDelegate {
hope this code will solve your problem.
How about two side by side or overlapping text fields? One could be editable, the other not. You could adjust borders to make it look seamless.