You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中TextField输入时格式化INR货币缺失千位分隔符问题

解决印度卢比(INR)输入时的千位分隔符格式化问题

你的代码核心问题在于直接将带符号和分隔符的格式化字符串赋值给了TextField绑定的变量,导致后续输入时字符串包含非数字字符,无法被正确解析,同时也破坏了输入逻辑。以下是两种可行的修正方案:

方案一:自定义Binding分离数据与显示

通过自定义Binding,将用户输入的纯数字与显示的格式化字符串分开处理,既保证输入体验,又能正确显示千位分隔符:

import SwiftUI

extension NumberFormatter {
    static var indianRupeeFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.locale = Locale(identifier: "en_IN")
        formatter.maximumFractionDigits = 0
        formatter.usesGroupingSeparator = true
        // 依赖locale自动处理货币符号、分隔符,无需手动设置
        return formatter
    }
}

struct CurrencyTextFieldView: View {
    @State private var amount: Double = 0
    @State private var rawInput: String = ""
    
    private var amountBinding: Binding<String> {
        Binding(
            get: {
                NumberFormatter.indianRupeeFormatter.string(from: NSNumber(value: amount)) ?? "₹0"
            },
            set: { newValue in
                // 过滤所有非数字字符,只保留输入的数字
                let digits = newValue.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
                rawInput = digits
                // 转换为数字并更新状态
                amount = Double(digits) ?? 0
            }
        )
    }
    
    var body: some View {
        TextField("₹0", text: amountBinding)
            .keyboardType(.numberPad)
            .onChange(of: rawInput) { _ in
                // 强制更新显示为格式化后的内容
                amountBinding.wrappedValue = NumberFormatter.indianRupeeFormatter.string(from: NSNumber(value: amount)) ?? "₹0"
            }
    }
}

方案二:简化版输入过滤与格式化

直接在输入变化时过滤非数字字符,再进行格式化,逻辑更简洁:

import SwiftUI

extension NumberFormatter {
    static var inrCurrency: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "en_IN")
        formatter.numberStyle = .currency
        formatter.maximumFractionDigits = 0
        return formatter
    }
}

struct ContentView: View {
    @State private var testAmount = ""
    
    var body: some View {
        TextField("₹ 0", text: $testAmount)
            .keyboardType(.numberPad)
            .onChange(of: testAmount) { newValue in
                // 只保留输入中的数字字符
                let cleanDigits = newValue.filter { $0.isNumber }
                // 转换为数字并格式化
                guard let amount = Double(cleanDigits) else {
                    testAmount = "₹0"
                    return
                }
                testAmount = NumberFormatter.inrCurrency.string(from: NSNumber(value: amount)) ?? "₹0"
            }
    }
}

关键说明

  • 原代码中,当第一次输入1200后,testAmount会被设置为₹1,200,后续用户再输入时,这个字符串包含₹和,,无法被Double()解析,导致格式化逻辑失效。
  • 两种方案都先过滤掉非数字字符,确保处理的是纯数字,再通过en_IN locale自动处理印度卢比的千位分隔符规则,无需手动设置分隔符和符号。

内容的提问来源于stack exchange,提问作者Joji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:23:15