Sum of three textfield value without clicking a button (Swift - Xcode)
One way is to add self
as the target to the text fields, for the control event .editingChanged
impact.addTarget(self, action: #selector(textChanged), for: .editingChanged)
// do the same for other textfields
Then declare a textChanged
method. This should handle what happens when the texts in the text fields change. One implementation would be to add up all the values in the text fields (if any, and is valid) and display it in the label.
func textChanged() {
let impactValue = Int(impact.text!)
let rigourValue = Int(rigour.text!)
let responseValue = Int(response.text!)
total.text = String(describing:
(impactValue ?? 0) + (rigourValue ?? 0) + (responseValue ?? 0)
)
}
Optionally, you can conform to UITextFieldDelegate
:
class TryingoutController: UIViewController, UITextFieldDelegate {
}
and implement shouldChange
according to this answer by Thuggish Nuggets. Then, set the delegate
s of the text fields to self
:
impact.delegate = self
// do the same for other text fields.
Sum of multiple UITextfields without a button action
First set delegate self to your textfield
- (void)viewDidLoad
{
[super viewDidLoad];
[firstTextField setDelegate:self];
[secondTextField setDelegate:self];
[thirdTextField setDelegate:self];
}
Calculate your total in following method.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
total.text = [NSString stringWithFormat:@"d",([firstTextField.text intValue])+([secondTextField.text intValue])+([thirdTextField.text intValue])];
return YES;
}
Sum up every digit in UITextField in Swift
Let's say you have following date string in your text field.
var dateString = "19/09/2018"
let sum = dateString.reduce(0) { (res, char) -> Int in
var res = res
if let number = Int(String(char)) {
res+=number
}
return res
}
print(sum) ==> 30
And using segue method you can just pass this sum to your next VC.
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { }
best way to calculate the result of a multiple uitextfields
You can make good use of the nil coalescing operator ??
to handle the cases where your textfields are empty or don't contain legal values:
let value1 = Int(textfield1.text ?? "") ?? 0
let value2 = Int(textfield2.text ?? "") ?? 0
let value3 = Int(textfield3.text ?? "") ?? 0
let value4 = Int(textfield4.text ?? "") ?? 0
let sum = value1 + value2 + value3 + value4
Or for a functional approach, collect the textfield
s in an array literal and use flatMap
and reduce
to convert the values and produce the sum:
let values = [textfield1, textfield2, textfield3, textfield4].flatMap({$0.text}).flatMap({Int($0)})
let sum = values.reduce(0, +)
what's the easiest way to add the value of two text fields to equal a sum to a label
You can use the power of functional swift like this:
if let textField1String = textField1.text, let textField2String = textField2.text {
let arr = [textField1String, textField2String]
let result = arr.compactMap({ Int($0) }).reduce(0, +) //Cast in Int value + using reduce to sum all the values of array
speedLabel.text = "\(result)"
}
Set the maximum character length of a UITextField
While the UITextField
class has no max length property, it's relatively simple to get this functionality by setting the text field's delegate
and implementing the following delegate method:
Objective-C
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Prevent crashing undo bug – see note below.
if(range.length + range.location > textField.text.length)
{
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return newLength <= 25;
}
Swift
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentCharacterCount = textField.text?.count ?? 0
if range.length + range.location > currentCharacterCount {
return false
}
let newLength = currentCharacterCount + string.count - range.length
return newLength <= 25
}
Before the text field changes, the UITextField asks the delegate if the specified text should be changed. The text field has not changed at this point, so we grab it's current length and the string length we're inserting (either through pasting copied text or typing a single character using the keyboard), minus the range length. If this value is too long (more than 25 characters in this example), return NO
to prohibit the change.
When typing in a single character at the end of a text field, the range.location
will be the current field's length, and range.length
will be 0 because we're not replacing/deleting anything. Inserting into the middle of a text field just means a different range.location
, and pasting multiple characters just means string
has more than one character in it.
Deleting single characters or cutting multiple characters is specified by a range
with a non-zero length, and an empty string. Replacement is just a range deletion with a non-empty string.
A note on the crashing "undo" bug
As is mentioned in the comments, there is a bug with UITextField
that can lead to a crash.
If you paste in to the field, but the paste is prevented by your validation implementation, the paste operation is still recorded in the application's undo buffer. If you then fire an undo (by shaking the device and confirming an Undo), the UITextField
will attempt to replace the string it thinks it pasted in to itself with an empty string. This will crash because it never actually pasted the string in to itself. It will try to replace a part of the string that doesn't exist.
Fortunately you can protect the UITextField
from killing itself like this. You just need to ensure that the range it proposes to replace does exist within its current string. This is what the initial sanity check above does.
swift 3.0 with copy and paste working fine.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let str = (textView.text + text)
if str.characters.count <= 10 {
return true
}
textView.text = str.substring(to: str.index(str.startIndex, offsetBy: 10))
return false
}
Hope it's helpful to you.
How to set up UITextFieldDelegate for multiple text fields?
If your goal is to have all three text fields follow the same rule, set the delegate
for all three. The shouldChangeCharactersIn
only needs to check the “current” text field into which the user is currently typing.
A minor observation, but I also would avoid recreating the CharacterSet
of allowed characters repeatedly. You can simply make that a property.
That reduces it down to something like:
private let allowedCharacters = CharacterSet(charactersIn: "ABCDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.count ?? 0) - range.length + string.count > 1 {
return false
}
return allowedCharacters.isSuperset(of: CharacterSet(charactersIn: string.localizedUppercase))
}
If you want them only entering uppercase characters, I would:
Change the keyboard capitalization to “All Characters”, so they are more likely to not enter lowercase letters:
Optionally change the capitalization by adding an “editing changed” action for your text field to:
@IBAction func editingChanged(_ textField: UITextField) {
textField.text = textField.text?.localizedUppercase
}You might have to experiment whether you want to use
localizedUppercase
oruppercased()
oruppercased(with:)
.Note, this “uppercase the whole string” logic is a little sloppy. If you were allowing multi-character strings in your input, you really would want to capture where the cursor was and restore it. (Otherwise it could be an annoying UX where if the user is changing the first character of a multi-character string, the cursor would jump to the end.) E.g., a simple rendition might be:
@IBAction func editingChanged(_ textField: UITextField) {
let range = textField.selectedTextRange
textField.text = textField.text?.localizedUppercase
textField.selectedTextRange = range
}But for your single character input, the simpler example, above, should be sufficient.
Related Topics
Swift Radio Streaming Avplayer
Enum Not Working in Custom Initializer
How to Scale/Position Nodes Swift Spritekit? Custom View
Uiimagepickercontroller Navigation Bar Tint Color Not Working with iOS 13
Codable/Decodable Should Decode Array with Strings
How to Create and Access Share App Group Document Directory
How to Set a Function as Function Argument in Swift 3
How to Compare Result to .Succeed in Swift
Filteredarrayusingpredicate Does Not Exist in Swift Array
With Swiftui, How to Constrain a View's Size to Another Non-Sibling View
How to Get Rid of Array Brackets While Printing
Limiting Concurrent Access to a Service Class with Rxswift
How to Encode and Decode the Closures