Home > Back-end >  How to filter text in UITextField
How to filter text in UITextField

Time:09-09

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
  • Related