How to build NumberField in SwiftUI?

163 Views Asked by At

I'm working on MacOS and I try to make NumberField — something like TextField, but for numbers. In rather big tree of views at the top I had:

 ...
 VStack {
      ForEach(instances.indices, id:\.self) {index in
         TextField("",
            text: Binding( 
                get: {"\(String(format: "%.1f", instances[index].values[valueIndex]))"},
                set: {setValueForInstance(index, valueIndex, $0)})
             )                   
       }
 }
 ...

And it worked well, but not nice:

  • ✔︎ when I changed value, all View structure was redrawn – good
  • ✔︎ values was updated if they were changed by another part of Views structure – good
  • ✖︎ it was updated after each keypresses, which was annoying, when I tried to input 1.2, just after pressing 1 view was updated to 1.0. Possible to input every number but inconvenient – bad

So, I tried to build NumberField.

    var format = "%.1f"
    struct NumberField : View {
        @Binding var number: Double {
            didSet {
                stringNumber = String(format: format, number)
            }
        }
        @State var stringNumber: String
        var body: some View {
            TextField("" , text: $stringNumber, onCommit: {
                print ("Commiting")
                if let v = Double(stringNumber) {
                    number = v
                } else {
                    stringNumber = String(format:format, number)
                }
                print ("\(stringNumber) , \(number)" )
            })
        }
        init (number: Binding<Double>) {
            self._number = number
            self._stringNumber = State(wrappedValue: String(format:format, number.wrappedValue))
        }
    }

And It's called from the same place as before:

 ...
 VStack {
      ForEach(instances.indices, id:\.self) {index in
         NumberField($instances[index].values[valueIndex])                  
       }
 }
 ...

But in this case it never updates NumberField View if values was changed by another part of View. Whats's wrong? Where is a trick?

0

There are 0 best solutions below