【问题标题】:Swift format input as percentage in "as-you-type" fashion以“as-you-type”方式将 Swift 格式输入作为百分比
【发布时间】:2022-01-03 00:07:57
【问题描述】:

我有一个文本字段,它调用一种方法,以按你输入的方式将输入格式化为百分比。

cell.textField.addTarget(self, action: #selector(textChangedIntoPercent(sender:)), for: .editingChanged)

调用的方法:

@objc func textChangedIntoPercent (sender : UITextField) {
    
    if let amountString = sender.text?.percentInputFormatting() {
        sender.text = amountString
    }
}

以下代码在输入带有尾随 % 符号的数字时效果很好。但是,当使用退格时,不会删除任何内容,字符串只是返回自身,最后一个数字不退格。如果我将光标的位置更改为就在百分号之前,我可以删除数字。

func percentInputFormatting() -> String {
 
    var number: NSNumber!
    let formatter = NumberFormatter()
    formatter.numberStyle = .decimal
    formatter.maximumFractionDigits = 2
    formatter.minimumFractionDigits = 2
    
    var amountWithPrefix = self
    
    let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
    amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, self.count), withTemplate: "")
    
    let double = (amountWithPrefix as NSString).doubleValue
    number = NSNumber(value: (double / 100))

    guard number != 0 as NSNumber else {
        return "0%"
    }
    
    return "\(formatter.string(from: number)!)" + "%"
}

【问题讨论】:

  • 你想要发生什么?允许用户用退格键删除百分号?这是否与您自动添加百分号的意图相矛盾...?
  • 我很抱歉造成混乱。不,我不希望 % 符号永远能够被删除,但我希望用户能够在百分号之前退格数字。这有意义吗?
  • 哦,好吧,我明白你的意思了。

标签: ios swift string uitextfield percentage


【解决方案1】:

使用shouldChangeCharactersIn 委托方法检测退格。事实上,我建议你在这个委托方法中实现整个事情,而不是 editingChanged 的操作。

首先,如果您还没有设置代理:

cell.textField.delegate = self

...

现在实现shouldChangeCharactersIn。当用户以某种方式编辑文本字段时,将调用此方法,但 before 文本字段的文本实际上发生了变化。您可以从参数rangestring 中获取用户尝试进行的更改。用户正在尝试将textField.text 中的“range”范围替换为string 中的字符串。

如果string 为空,则表示用户正在尝试删除内容。我们删除最后一个数字,并再次格式化数字。否则,使用replacingCharacters(in: range, with: string) 应用用户的编辑,并检查它是否为有效数字。如果是,请格式化。

我们应该返回一个Bool 指示是否应该应用编辑。在这种情况下,由于文本字段的文本应如何更改 100% 由我们处理,因此我们不想应用用户的编辑。

extension YourViewController: UITextFieldDelegate {
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let oldText = textField.text else { return false }

        if string.isEmpty { // this means that backspace is pressed
            let oldDigits = textField.text?.digits
            // drops one digit every time backspace is pressed
            let newNumber = Double(oldDigits.dropLast()) ?? 0
            textField.text = percentFormatter.string(for: newNumber / 10000)
        } else // something has been entered
            if let newNumber = Double(
                    (oldText as NSString).replacingCharacters(in: range, with: string).digits
                  ) {
            textField.text = percentFormatter.string(for: newNumber / 10000)
        }
        return false
    }
}

percentFormatterwithoutNonDigits 是:

let percentFormatter: NumberFormatter = {
    let f = NumberFormatter()
    f.minimumFractionDigits = 2
    f.maximumFractionDigits = 2
    f.numberStyle = .percent
    f.locale = Locale(identifier: "en-US_POSIX")
    return f
}()

extension String {
    var digits: String {
        filter { "0"..."9" ~= $0 }
    }
}

【讨论】:

  • @LeoDabus 你知道吗,我已经厌倦了实现删除多个字符的复杂退格功能。我发现有太多边缘情况需要处理。无论如何,我觉得这有点超出了这个问题的范围。我只是要删除最后一个数字,否则将其设为 0。:)
  • 从未说过它在问题的范围内。我的评论只是仅供参考
猜你喜欢
  • 1970-01-01
  • 2018-04-21
  • 2019-12-28
  • 2015-09-30
  • 2016-03-13
  • 1970-01-01
相关资源
最近更新 更多