How do you dynamically format a number to have commas in a UITextField entry?

前端 未结 9 1953
傲寒
傲寒 2020-12-08 17:42

I want to have commas dynamically added to my numeric UITextField entry while the user is typing.

For example: 123,456 and 12,345,678

相关标签:
9条回答
  • 2020-12-08 18:17

    Here is a solution in swift 4.

     @objc func textFieldValDidChange(_ textField: UITextField) {
        let formatter = NumberFormatter()
        formatter.numberStyle = NumberFormatter.Style.decimal
        if textField.text!.count >= 1 {
           let number = Double(bottomView.balanceTxtField.text!.replacingOccurrences(of: ",", with: ""))
            let result = formatter.string(from: NSNumber(value: number!))
            textField.text = result!
        }
    }
    

    Don't forget to add editingChanged action as below:

    textField.addTarget(self, action:#selector(ViewController.textFieldValDidChange), for: .editingChanged)
    
    0 讨论(0)
  • 2020-12-08 18:18

    Here is a version in Swift 4. I used it for integers, I didn't check with decimal numbers.

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
         // Uses the number format corresponding to your Locale
         let formatter = NumberFormatter()
         formatter.numberStyle = .decimal
         formatter.locale = Locale.current
         formatter.maximumFractionDigits = 0
    
    
        // Uses the grouping separator corresponding to your Locale
        // e.g. "," in the US, a space in France, and so on
        if let groupingSeparator = formatter.groupingSeparator {
    
            if string == groupingSeparator {
                return true
            }
    
    
            if let textWithoutGroupingSeparator = textField.text?.replacingOccurrences(of: groupingSeparator, with: "") {
                var totalTextWithoutGroupingSeparators = textWithoutGroupingSeparator + string
                if string.isEmpty { // pressed Backspace key
                    totalTextWithoutGroupingSeparators.removeLast()
                }
                if let numberWithoutGroupingSeparator = formatter.number(from: totalTextWithoutGroupingSeparators),
                    let formattedText = formatter.string(from: numberWithoutGroupingSeparator) {
    
                    textField.text = formattedText
                    return false
                }
            }
        }
        return true
    }
    

    The big advantage of this method is that it uses the grouping separator defined in your current locale (region), because not everybody uses the comma as a grouping separator.

    Works with 0, backspace, but, again, I didn't test it with decimals. You are free to enhance this code if you worked it out with decimals.

    Examples:

    • Enter : "2" -> "2"
    • Enter : "3" -> "23"
    • Enter : "6" -> "236"
    • Enter : "7" -> "2,367"
    • Enter : "0" 3 times -> "2,367,000"
    • Backspace -> "236,700"

    Starting 0 works too:

    • Enter : "0" -> "0"
    • Enter : "2" -> "2"
    0 讨论(0)
  • 2020-12-08 18:19

    I have another one. Fix some bugs with local configuration and zero after decimal point

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        
        let point = Locale.current.decimalSeparator!
        let decSep = Locale.current.groupingSeparator!
        
        
        let text = textField.text!
        let textRange = Range(range, in: text)!
        
        var fractionLength = 0
        var isRangeUpperPoint = false
        
        if let startPoint = text.lastIndex(of: point.first!) {
            let end = text.endIndex
            let str = String(text[startPoint..<end])
            fractionLength = str.count
            isRangeUpperPoint = textRange.lowerBound >= startPoint
        }
        
        if  fractionLength == 3 && string != "" && isRangeUpperPoint {
            return false
        }
        
        let r = (textField.text! as NSString).range(of: point).location < range.location
        if (string == "0" || string == "") && r {
            return true
        }
        
        // First check whether the replacement string's numeric...
        let cs = NSCharacterSet(charactersIn: "0123456789\(point)").inverted
        let filtered = string.components(separatedBy: cs)
        let component = filtered.joined(separator: "")
        let isNumeric = string == component
        
        
        if isNumeric {
            let formatter = NumberFormatter()
            formatter.numberStyle = .decimal
            formatter.maximumFractionDigits = 2
            // Combine the new text with the old; then remove any
            // commas from the textField before formatting
            
            
            let newString = text.replacingCharacters(in: textRange,  with: string)
            
            
            let numberWithOutCommas = newString.replacingOccurrences(of: decSep, with: "")
            let number = formatter.number(from: numberWithOutCommas)
            if number != nil {
                var formattedString = formatter.string(from: number!)
                // If the last entry was a decimal or a zero after a decimal,
                // re-add it here because the formatter will naturally remove
                // it.
                if string == point && range.location == textField.text?.count {
                    formattedString = formattedString?.appending(point)
                }
                textField.text = formattedString
            } else {
                textField.text = nil
            }
        }
        
        
        
       return false
        
    }
    
    0 讨论(0)
提交回复
热议问题