Search code examples
iosswiftswift3

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!


Solution

  • 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)
      
      }