chickenparm chickenparm - 2 months ago 65
iOS Question

Limit Text Field to one decimal point input, numbers only, and two characters after the decimal place - Swift 3

I am struggling to do this with Swift 3. I have a text field that I would like to limit to only numbers and one decimal point and two characters after the decimal place. I would also like to have it work in regions where a decimal point is not used when entering non-integers. Thank you for any suggestions!

Answer

You need to assign delegate to your textfield and in the shouldChangeCharactersIn delegate method do your validations:

  1. Add extension with validation methods for the string:

    extension String{
    
        private static let decimalFormatter:NumberFormatter = {
            let formatter = NumberFormatter()
            formatter.allowsFloats = true
            return formatter
        }()
    
        private var decimalSeparator:String{
            return String.decimalFormatter.decimalSeparator ?? "."
        }
    
        func isValidDecimal(maximumFractionDigits:Int)->Bool{
    
            // Depends on you if you consider empty string as valid number
            guard self.isEmpty == false else {
                return true
            }
    
            // Check if valid decimal
            if let _ = String.decimalFormatter.number(from: self){
    
                // Get fraction digits part using separator
                let numberComponents = self.components(separatedBy: decimalSeparator)
                let fractionDigits = numberComponents.count == 2 ? numberComponents.last ?? "" : ""
                return fractionDigits.characters.count <= maximumFractionDigits
            }
    
            return false
        }
    
    }
    
  2. In your delegate method:

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
        // Get text
        let currentText = textField.text ?? ""
        let replacementText = (currentText as NSString).replacingCharacters(in: range, with: string)
    
        // Validate
        return replacementText.isValidDecimal(maximumFractionDigits: 2)
    
    }