How to restrict the value range of a field to between 1 and 100

Hi,

This involves four fields on a view. Three of the fields are controlled to present a currency value with the sum of two of the fields (paidFld and shippingFld) been put into a third (totalFld) field. This part works fine. I'm just including it for clarity purposes.


The fourth field (conditionFld) adds a % to the end of the input and the length of the input is restricted to 3 or less characters. This is handeled in the extension.


My question is, how to restrict the input of the conditionFld to be a number between 1 and 100? The keyboard type of this field is set to number pad.


Thanks for the help.

Tom


class ViewController: UIViewController
{
    @IBOutlet weak var conditionFld: UITextField!
    @IBOutlet weak var paidFld: UITextField!
    @IBOutlet weak var shippingFld: UITextField!
    @IBOutlet weak var totalField: UITextField!
   
    let Condition_Field_Length = 3
   
    override func viewDidLoad()
    {
        super.viewDidLoad()
       
        hideKeyboard()
    }
   
    func convert(theField: UITextField)
    {
        let paidStr: String = theField.text!
        let tempPaid = (paidStr as NSString).doubleValue
       
        if theField.text! == ""
        {
            return
        } else if let theDouble = convertCurrencyToDouble(input: theField.text!) {
            theField.text = convertDoubleToCurrency(amount: theDouble)
        } else {
            theField.text = convertDoubleToCurrency(amount: tempPaid)
        }
    }
   
    func convertCurrencyToDouble(input: String) -> Double?
    {
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .currency
        numberFormatter.locale = Locale.current
       
        return numberFormatter.number(from: input)?.doubleValue
    }
   
    func convertDoubleToCurrency(amount: Double) -> String
    {
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .currency
        numberFormatter.locale = Locale.current
       
        return numberFormatter.string(from: NSNumber(value: amount))!
    }
   
    @IBAction func conditionEditingBegin(_ sender: UITextField)
    {
        let theString: String = sender.text!
       
        if sender.keyboardType == .numberPad
        {
            if theString != ""
            {
                let newString = String.init(theString.dropLast() )
               
                sender.text = newString
            }
        }
    }
   
    @IBAction func conditionEditingEnded(_ sender: UITextField)
    {
        let theString: String? = sender.text
       
        if sender.keyboardType == .numberPad
        {
            if theString != ""
            {
                if theString?.suffix(1) != "%"
                {
                    sender.text = "\(theString!)%"
                }
            } else {
                sender.text = ""
            }
        }
    }
   
    @IBAction func paidEditingEnded(_ sender: UITextField)
    {
        convert(theField: sender)
       
        let paidStr: String = paidFld.text!
        let shippingStr: String = shippingFld.text!
       
        let tPaid = convertCurrencyToDouble(input: paidStr)
        let tShip = convertCurrencyToDouble(input: shippingStr)
       
        let theTotalText = (Double(tPaid ?? 0.0) + Double(tShip ?? 0.0))
        if theTotalText != 0.0 {
            totalField.text = convertDoubleToCurrency(amount: theTotalText)
        } else {
            totalField.text = ""
        }
    }
}

extension UIViewController
{
    func hideKeyboard()
    {
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(
            target: self,
            action: #selector(UIViewController.dismissKeyboard))
       
        tap.cancelsTouchesInView = false
        view.addGestureRecognizer(tap)
    }
   
    @objc func dismissKeyboard()
    {
        view.endEditing(true)
    }
}

extension ViewController: UITextFieldDelegate
{
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
    {
        // This is for the condition field
        if textField.tag == 1
        {
            // How do I restrict the number values to be between 1 and 100
            return (textField.text?.count ?? 0) + string.count - range.length <= Condition_Field_Length
        } else {
           
            // This if for the paid and shipping fields
            guard let text = textField.text, let decimalSeparator = NSLocale.current.decimalSeparator else {
                return true
            }
           
            var splitText = text.components(separatedBy: decimalSeparator)
            let totalDecimalSeparators = splitText.count - 1
            let isEditingEnd = (text.count - 3) < range.lowerBound
           
            splitText.removeFirst()
           
            // Check if it will exceed 2 dp
            if splitText.last?.count ?? 0 > 1 && string.count != 0 && isEditingEnd
            {
                return false
            }
           
            // If there is already a decimalSeparator we don't want to allow further decimalSeparator
            if totalDecimalSeparators > 0 && string == decimalSeparator
            {
                return false
            }
            // Keyboard is set to deciaml pad
            return true
        }
    }
}
Answered by DTS Engineer in 423189022

A few words of warning here:

  • If you check the validity of numbers use APIs that only support standard ASCII digits, like

    Int("123")
    , things will fail if the user enters non-ASCII digits (most notably, Eastern Arabic digits). A better option here is to use
    NumberFormatter
    to parse the number.
  • Preventing folks from typing a ‘wrong’ value can be quite annoying. For example, imagine I want to enter 15 but I accidentally transpose the digits. Depending on the specific environment it may be more convenient to go from 51 to 151 to 15, but that’ll fail with your setup. IMO a better UI is to accept anything in the field and then show a status value indicating whether the value is valid or not (and, if not, explaining the error).

    As a side benefit, that code is much easier to write.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Restricting the value of a textField is not so easy as expected, but in your case this might work:

        if textField.tag == 1 {
            // How do I restrict the number values to be between 1 and 100
            let text = textField.text ?? ""
            let updatedText = text.replacingCharacters(in: Range(range, in: text)!, with: string)
            if let intValue = Int(updatedText), 1 <= intValue && intValue <= 100 {
                return true
            } else {
                return false
            }
        } else {
            //...
Accepted Answer

A few words of warning here:

  • If you check the validity of numbers use APIs that only support standard ASCII digits, like

    Int("123")
    , things will fail if the user enters non-ASCII digits (most notably, Eastern Arabic digits). A better option here is to use
    NumberFormatter
    to parse the number.
  • Preventing folks from typing a ‘wrong’ value can be quite annoying. For example, imagine I want to enter 15 but I accidentally transpose the digits. Depending on the specific environment it may be more convenient to go from 51 to 151 to 15, but that’ll fail with your setup. IMO a better UI is to accept anything in the field and then show a status value indicating whether the value is valid or not (and, if not, explaining the error).

    As a side benefit, that code is much easier to write.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

In addition to eskimo advice, I just play a beep during typing if there is a typing error. User may thus correct immediately or proceed and correct later once having seen the error message.

Thanks you for the reply. I this case the user knows they are typing in a % value. So wouldn't they be expecting to need to enter a value from 1 to 100?

Hi OOPer,

This is very close. However, there are 2 things I'd would like to address.

As it is the code allows to enter a string of zeros. 00000000000

Also, it does not allow for the user to delete all of the characters and leave he filed empty.

I added a clear button while editing but won't the user expect to be able to delete all the characters?


Thnaks,

Tom

Sure they should.


But there can always be a mistype and it is important for user to be notified of his error.

Thanks for your reply, and I know the behavior you addressed exactly.

I was planning to tell you that when you had replied and had not noticed that.


Anyway, you may need to re-design your requirement reading eskimo's suggestion.


Or, if you want to go this way further, you can freely customize the code I have shown.

OK, thank you. I apreacite the information.

How to restrict the value range of a field to between 1 and 100
 
 
Q