自定义百分比字段 UiTextField

custom percentage field UiTextField

我有一个文本字段委托方法,我的用例是:-

  1. 如果 (.) 点不存在限制输入两个字符,因为 100% 不应该打折。

  2. 如果用户输入的是 1.99,如何更新委托方法使其在 (.)

    后取两个数字
  3. 相同,如果输入是 12.99 如何更新委托方法,它应该在 (.)

    之后取两个数字
 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            
            guard !string.isEmpty else {
                return true
            }
            
            // maximum limit of input 2 as 100% should not be discount.
            if !textField.text!.contains(".") {
                let maxLength = 2
                let currentString: NSString = (textField.text ?? "") as NSString
                let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
                return newString.length <= maxLength

            } else {
                 // if there is (.)
                 let maxLength = 3
                let currentString: NSString = (textField.text ?? "") as NSString
                let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString
                return newString.length <= maxLength
            }
            
        }

这就是答案

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            guard !string.isEmpty else {
                return true
            }
            let newText = (textField.text! as NSString).replacingCharacters(in: range, with: string) as String
            if let num = Double(newText), num >= -1 && num <= 100 {
                return true
            } else {
                return false
            }
    
        }

一种选择是跟踪小数点前后的位数,并确定您是否已达到阈值。

您的回答没有任何问题,但如果您愿意,这里还有一个替代选项。您可以使用正则表达式,因为有时会跟踪多个布尔值、计数、变量可能有一些边缘情况。

我的 REGEX 技能不是太强,但这里有一个 nice SO thread 可以为您的问题获取一个 REGEX,您可能能够比我在下面使用的 REGEX 优化得更好。

private func isValidDecimal(_ text: String) -> Bool {
    
    // ^ $ - Anchors to analyze the text as one chunk / block
    // \d{1,2}) - Match a string that has 1 or 2 characters
    // | - OR
    // \d{1,2}\.{1}(\d{1,2})?
    // - \d{1,2} - Match a string that has 1 or 2 characters
    // - \.{1} - followed by a max of 1 decimal
    // - (\d{1,2})? - followed by 0 - 2 characters after the decimal
    let pattern = "^(\d{1,2}\.{1}(\d{1,2})?|\d{1,2})$"
    
    do
    {
        let regex = try NSRegularExpression(pattern: pattern)
        
        let matches = regex.matches(in: text,
                                    options: NSRegularExpression.MatchingOptions(),
                                    range: NSRange(location: 0,
                                                   length: text.count))
        
        // We only want 1 match as more than one match
        // would mean error
        return matches.count == 1
    }
    catch
    {
        // handle errors
        print("error")
    }
    
    return false
}
extension TextHighlightVC: UITextFieldDelegate {
    
    func textField(_ textField: UITextField,
                   shouldChangeCharactersIn range: NSRange,
                   replacementString string: String) -> Bool {
        
        guard let text = textField.text else { return false }
        
        return isValidDecimal(text + string)
    }
}

请注意,这可能不是最佳的 REGEX 模式,它只是向您展示一个选项。

这是似乎适用于所有用例的结果

根据 Omar 的评论更新:

one question if I press .5 at starting, textfield should show 0.5 how to achieve this using same regex

我认为我们可以将其作为 edge 案例处理,而不是使用正则表达式来处理,因为这对我来说似乎更容易。

我们检查输入的第一个字符是否为小数,然后添加 0。

这是我会做的:

extension TextHighlightVC: UITextFieldDelegate {
    
    func textField(_ textField: UITextField,
                   shouldChangeCharactersIn range: NSRange,
                   replacementString string: String) -> Bool {
        
        guard let text = textField.text else { return false }
        
        // Check if the first character entered is a decimal
        if text.count == 0 && string == "." {
            
            // Add 0 to the text field
            textField.text = "0"
            return true
        }
        
        return isValidDecimal(text + string)
    }
}