简体   繁体   English

将文本字段限制为一位小数点输入,仅限数字,小数点后两位字符 - Swift 3

[英]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.我正在努力使用 Swift 3. 我有一个文本字段,我想将其限制为仅数字和一个小数点以及小数点后两个字符。 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!感谢您的任何建议!

You need to assign delegate to your textfield and in the shouldChangeCharactersIn delegate method do your validations:您需要将委托分配给您的文本字段,并在 shouldChangeCharactersIn 委托方法中进行验证:

  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) }
 var number = Double(yourTextfield.text)
 if number != nil {
   //if user enters more than 2 digits after the decimal point it will round it up to 2
   let roundedNumber = Double(num!).roundTo(places: 2)  
 }
 else {
//probably print an error message
}

If you are using Swift UI then the complete solution如果您使用的是 Swift UI 那么完整的解决方案

  1. TextField allow numeric value only TextField 只允许数值
  2. Should accept only one comma (".")应该只接受一个逗号 (".")
  3. Restrict decimal point upto x decimal place限制小数点最多 x 位小数

File NumbersOnlyViewModifier文件编号OnlyViewModifier

import Foundation
import SwiftUI
import Combine
struct NumbersOnlyViewModifier: ViewModifier {
    
    @Binding var text: String
    var includeDecimal: Bool
    var digitAllowedAfterDecimal: Int = 1
    
    func body(content: Content) -> some View {
        content
            .keyboardType(includeDecimal ? .decimalPad : .numberPad)
            .onReceive(Just(text)) { newValue in
                var numbers = "0123456789"
                let decimalSeparator: String = Locale.current.decimalSeparator ?? "."
                if includeDecimal {
                    numbers += decimalSeparator
                }
                if newValue.components(separatedBy: decimalSeparator).count-1 > 1 {
                    let filtered = newValue
                    self.text = isValid(newValue: String(filtered.dropLast()), decimalSeparator: decimalSeparator)
                } else {
                    let filtered = newValue.filter { numbers.contains($0)}
                    if filtered != newValue {
                        self.text = isValid(newValue: filtered, decimalSeparator: decimalSeparator)
                    } else {
                        self.text = isValid(newValue: newValue, decimalSeparator: decimalSeparator)
                    }
                }
            }
    }
    
    private func isValid(newValue: String, decimalSeparator: String) -> String {
        guard includeDecimal, !text.isEmpty else { return newValue }
        let component = newValue.components(separatedBy: decimalSeparator)
        if component.count > 1 {
            guard let last = component.last else { return newValue }
            if last.count > digitAllowedAfterDecimal {
                let filtered = newValue
               return String(filtered.dropLast())
            }
        }
        return newValue
    }
}

File View+Extenstion文件查看+扩展

extension View {
    func numbersOnly(_ text: Binding<String>, includeDecimal: Bool = false) -> some View {
        self.modifier(NumbersOnlyViewModifier(text: text, includeDecimal: includeDecimal))
    }
} 

File ViewFile文件查看文件

 TextField("\(count, specifier: Constants.FloatFormat.twoDecimalFloat)", text: $value,  onEditingChanged: { isEditing in
      self.isEditing = isEditing
   })

  .foregroundColor(Color.neutralGray900)
  .numbersOnly($value, includeDecimal: true)
  .font(.system(size: Constants.FontSizes.fontSize22))
  .multilineTextAlignment(.center)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM