Текстовое поле не обновляется - PullRequest
0 голосов
/ 03 марта 2020

следующий код загружается нормально, текст и двойное поле оба показывают 300. однако, когда я нажимаю кнопку отправить, текст меняется только на 0. В выводе на печать вы увидите, что init был вызван с новым значением 0, но это не обновляет двойное поле? какие-либо предложения?

import SwiftUI

struct ContentView: View {
    @State var amount:Double = 300
    var body: some View {
        VStack {
            Text("\(self.amount)")
            DoubleField(value: $amount)
            Button(action: {self.amount=0}) {Text("Submit")}
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

struct DoubleField:View {

    @Binding var doubleValue:Double
    @State var stringValue:String

    init(value: Binding<Double>) {
        print("DoubleField.init(value: \(value.wrappedValue))")
        self._doubleValue = value
        self._stringValue = State(initialValue: "\(value.wrappedValue)")
    }

    var body: some View {
        TextField("0.00", text: $stringValue)
    }

}

1 Ответ

0 голосов
/ 03 марта 2020

SwiftUI не подозревает, что внутреннее состояние DoubleField View изменилось. В то время, когда вы устанавливаете _stringValue, экземпляр DoubleField все еще не существует, поэтому вы не можете написать stringValue = ... в init (..) Оболочка свойства состояния может сообщить SwiftUI только после инициализации, что его обернут значение было изменено, не раньше.

попробуйте следующее

import SwiftUI

struct ContentView: View {
    @State var amount:Double = 300
    var body: some View {
        VStack {
            Text("\(self.amount)")
            DoubleField(value: $amount).id(amount)
            Button(action: {
                self.amount += 10
            }) { Text("Submit") }
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

struct DoubleField:View {

    @Binding var doubleValue:Double
    @State var stringValue:String
    init(value: Binding<Double>) {
        print("DoubleField.init(value: \(value.wrappedValue))")
        self._doubleValue = value
        self._stringValue = State(initialValue: "\(value.wrappedValue)")
        print(stringValue)
    }

    var body: some View {
        VStack {
        Text(stringValue)
        TextField("20.00", text: $stringValue)
        }
    }

}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

все поля обновляются по мере необходимости, поскольку SwiftUI видит изменение из-за модификатора .id

В вашем case просто используйте

DoubleField(value: $amount).id(amount)

Это работает, потому что Double соответствует Hashable и будет пересчитывать свое тело только при изменении значения количества.

UPDATE

Вы можете создать пользовательскую привязку, как я сделал в следующем примере. Это Binding with backend Double, заключенный в @State (для информирования SwiftUI о любом изменении его значения)

let binding = Binding<String>(get: {
            if self.empty { return "" } else {
                return self.format(value: self.value.value)
            }
        }) { (str) in
            self.empty = str.isEmpty
            // before string to double
            // replace decimal separator to "." !!!
            let dot = Locale.current.decimalSeparator ?? "."
            let s = str.replacingOccurrences(of: dot, with: ".")
            self.value.value = Double(s) ?? 0.0
        }

где

func format(value: Double) -> String {
        // for presentation
        // replace "." with decimal separator
        let dot = Locale.current.decimalSeparator ?? "."
        var s = String(format: "%f", value)
        .replacingOccurrences(of: ".", with: dot)
        .reversed()
        .drop(while: {$0 == "0"})
        .reversed()
        .map(String.init)
        .joined()

        if let last = s.last, String(last) == dot {
            s.removeLast()
        }
        return s
    }

Работает с TextField намного лучше, чем сборка Formatter -включает поддержку в TextField, а также поддерживает зависящий от локали десятичный разделитель

и пример использования enter image description here

использование

TextField ("0", текст : переплет)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...