即时编辑 SwiftUI TextField

问题描述

我希望能够在用户逐个字符键入时编辑文本字段。我希望能够在用户键入时输入数字字段:

  1. 过滤掉非数字字符,只返回已经输入的有效字符。
  2. 格式化数字,这样当用户输入时,他们会得到相反的数字。即 120.36 将显示为: 0.01 0.12 1.20 12.03 120.36

如果用户输入无效字符,则返回不包含无效字符的字符串。 我被困在如何捕获 TextField、编辑它并按照我显示的格式返回它。

我已经走了这么远:(不远:-) 我已经在 StackOverflow 上尝试了许多解决方案,但似乎没有一个让我想去我想去的地方.. 在编辑更改 onChange 等

struct SwiftUIView:视图 {

@State var amount: String = "0.00"
var body: some View {
    
    TextField(
        "Enter amount here ",text: $amount
    )

}

}

解决方法

我怀疑我的要求太宽泛了,可能有点想为我做编程。事实并非如此,但也许我可以将范围缩小一点。
无论如何,我能够达到我想要的结果。我认为这是一个巨大的 KLUDGE,但这是我所能想到的。

首先是我的 SwiftUI 视图:

struct SwiftUIView: View {

    @State var someText: String = "0.00"
    @State var oldText: String = ""
    @State var amount: Double = 0.00

    var body: some View {
    VStack {
        TextField("Enter some text here",text: $someText,onCommit: {
                    print("someText = \(someText)")
                    self.amount = Double(someText)!
                    }
        )
            .onChange(of: someText,perform: { value in
                    if someText != oldText {
                        someText = editInputNumber(textIn: someText)
                        oldText = someText
                    }
                }
            
            )
        
            Text("The amount entered was \(self.amount)")

            }
    }
}

使用 onChange 我遇到了以编程方式更改绑定字段第二次触发 onChange 的问题。这是 Kludge 的最大部分,我必须在其中测试对 onChange 的第二次调用。

然后是我创建的用于响应用户输入的函数。 这个函数是从视图中调用的,它接受字符串并首先调用一个函数将其过滤为仅数字。消除任何意外输入的非数字

它接受结果并将其提交给格式化函数并取回格式化的字符串。

func editInputNumber(textIn: String) -> String
{
        var fixedText = ""
        var charactersWork = [Character]()
        charactersWork = getNumericInputString(textIn: textIn)
        fixedText = formatDecimalNumericString(charactersWork: 
        charactersWork)
        return fixedText
}

将输入字符串过滤为仅数字的功能。它也过滤掉先前条目中的任何前导零。

func getNumericInputString(textIn: String) -> [Character]
{
        var leadingZero = true
        let charactersIn = Array(textIn)
        var charactersOut = [Character]()
        for i in 0..<charactersIn.count {
            if charactersIn[i].isNumber {
                if let number = Int(String(charactersIn[i]))
                {
                    if number > 0
                    {
                        leadingZero = false
                    }
                }
                if !leadingZero {
                    charactersOut.append(charactersIn[i])
                }
            }
        }

    return charactersOut
}

在字符串被过滤成只有数字的字符数组后,此函数将其格式化以输出回视图。如果是输入的前两个数字,则函数格式在值的前导零。

func formatDecimalNumericString(charactersWork: [Character]) - 
   > String
{
    let number: String = "000"
    var charactersOut = [Character]()
    if charactersWork.count < 3
    {
        charactersOut = Array(number)
    }

    if charactersWork.count > 0
    {
        if charactersWork.count == 1
        {
            charactersOut[2] = charactersWork[0]
        }
        if charactersWork.count == 2
        { 
            charactersOut[1] = charactersWork[0]
            charactersOut[2] = charactersWork[1]
        }
        if charactersWork.count > 2
        {
            for i in 0..<charactersWork.count
            {
                charactersOut.append(charactersWork[i])
            }
        }
        charactersOut.insert(".",at: (charactersOut.count - 2))
    }
    return String(charactersOut)
}