I have an @objc func
where I am trying to format the contents of a UITextField
whenever the user types into it. Essentially, I am trying to filter the user input so that you can only type integer numbers, as well as decimal numbers whenever the user types a .
on the text field, up to two digits. However, I am having trouble trying to get the @objc func
to work properly on the UITextField
.
Valid inputs would include something like: 100
, 324.54
, 4.01
, etc.
My code is below:
import UIKit
class ViewController: UIViewController {
let textField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
createTextField()
}
private func createTextField() {
view.addSubview(textField)
textField.layer.cornerRadius = 10
textField.layer.borderWidth = 2
textField.layer.borderColor = UIColor.systemGray4.cgColor
textField.textColor = .label
textField.tintColor = .label
textField.textAlignment = .center
textField.font = UIFont.preferredFont(forTextStyle: .title2)
textField.adjustsFontSizeToFitWidth = true // Font will shrink as text becomes longer.
textField.minimumFontSize = 12
textField.backgroundColor = .tertiarySystemBackground
textField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textField.centerYAnchor.constraint(equalTo: view.centerYAnchor),
textField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 50),
textField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -50),
textField.heightAnchor.constraint(equalToConstant: 50)
])
}
@objc func billVerification(input: UITextField) {
if let input = input.text {
var output = input.filter { "0123456789.".contains($0) }
if output.filter({ $0 == "." }).count > 1 { output = String(input.dropLast()) }
if output.contains(".") {
if output.components(separatedBy: ".")[1].count > 2 { output = String(input.dropLast()) }
}
}
}
}
How do I get the @objc func
to take effect on the UITextField
whenever the user types something? Any help would be greatly appreciated.
CodePudding user response:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
}
Above delegate method will get called right before the text inside the UITextField
get changed. Add. your code inside it.
This is another implementation I implemented which is bit different from yours. Check that one also.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//hamdle the maximum and minimum decimal counts
let formatter = NumberFormatter()
formatter.numberStyle = .none
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 0
textField.textColor = UIColor(red: -238.0/255, green: -87.0/255, blue: -61.0/255, alpha: 1.0)
let finalString = "\(textField.text ?? "")\(string)"
let dpRemovedString = finalString.filter{$0 != "."}
let dpCount = finalString.filter{$0 == "."}.count
//check for the decimal poin count
if dpCount > 1{
return false
}
//check there is only numbers
if CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: dpRemovedString)){
if dpRemovedString == ""{
return false
}
var formattedNumber = formatter.string(for: Double(finalString))
//here highest alllowed number is 999
if Float(formattedNumber!)! >= 999{
return false
}else{
if string == "."{
formattedNumber = formattedNumber! string
}
textField.text = formattedNumber
}
return false
}else{
return false
}
}
CodePudding user response:
I made it. Just replace your existing code with the code below:
class ViewController: UIViewController, UITextFieldDelegate {
let textField = UITextField()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
textField.delegate = self
createTextField()
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.text != "" || string != "" {
let res = (textField.text ?? "") string
return Double(res) != nil
}
return true
}
private func createTextField() {
view.addSubview(textField)
textField.layer.cornerRadius = 10
textField.layer.borderWidth = 2
textField.layer.borderColor = UIColor.systemGray4.cgColor
textField.textColor = .label
textField.tintColor = .label
textField.textAlignment = .center
textField.font = UIFont.preferredFont(forTextStyle: .title2)
textField.adjustsFontSizeToFitWidth = true // Font will shrink as text becomes longer.
textField.minimumFontSize = 12
textField.backgroundColor = .tertiarySystemBackground
textField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
textField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textField.centerYAnchor.constraint(equalTo: view.centerYAnchor),
textField.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 50),
textField.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -50),
textField.heightAnchor.constraint(equalToConstant: 50)
])
}
}
Like that it works just as you expected. What's happening here: you set your VC as a TextFieldDelegate so that it can call the function textField. The function's logic is fairly simple. You can also restrict the users keypad to one containing only digits and a decimal point like that
textField.keyboardType = .decimalPad