3

I want to limit the user input to only valid numbers and am using the following:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
    guard CharacterSet(charactersIn: " -0123456789.,\t\n").isSuperset(of: CharacterSet(charactersIn: text)) else {
        return false
    }
    return true
}

But this does not prevent entering more than one decimal point such as "1.2.3". Is there a simple way to prevent that?

Greg
  • 495
  • 4
  • 12

2 Answers2

0

Try to use this example

guard CharacterSet(charactersIn: " -0123456789.,\t\n").isSuperset(of: CharacterSet(charactersIn: text)) else {
        return false
    }
    
    var newText = (textView.text as NSString).replacingCharacters(in: range, with: text)
    newText = newText.replacingOccurrences(of: ",", with: ".")
    
    let strings = newText.split { character -> Bool in
        return character == "\t" || character == "\n"
    }
    
    let numbers: [Double] = strings.compactMap { Double($0) }
    
    return strings.count == numbers.count
0

This was answered for text fields by @whyceewhite several years ago. One approach is to use the NumberFormatter() to determine if the value is a a valid number.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .decimal
        return numberFormatter.number(from: textView.text + text) != nil
    }

Perhaps you also want to handle the case when a user enters a decimal as the first value of a number, which will return nil when put into number formatter. You can use something as follows:

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if (textView.text == nil || textView.text == "") && text == "." {
            textView.text = "0"
            return true
        } else {
            let numberFormatter = NumberFormatter()
            numberFormatter.numberStyle = .decimal
            return numberFormatter.number(from: textView.text + text) != nil
        }
    }

Which will check if the text field text is nil or empty and that the value to be inserted is a ., add a leading zero and then add the decimal.

cazman
  • 76
  • 2