Почему текстовое поле не следует за обновлением? (iOS 15)

#swiftui #ios15

Вопрос:

По какой-то причине текстовое поле перестало реагировать на изменения.

 struct ContentView: View {
    @State private var number: Int = 0
    
    private var bindingNumber: Binding<Int> {
        .init {
            self.number
        } set: {
            self.number = $0 % 10
        }

    }
    
    var body: some View {
        VStack {
            Text("number: (self.number)")
            TextField("Number", value: self.bindingNumber, formatter: NumberFormatter())
                .disableAutocorrection(true)
                .background(Color.gray)
        }
        .padding(.horizontal, 100)
    }
}
 

если вы введете «44444» и завершите редактирование, текстовое поле не изменит свое значение на «4».
В iOS 14 этот код работает правильно.

Вот еще один пример:

 struct ContentView: View {
    @State private var number: Int = 0
    @State private var numberRaw: Int = 0

    var body: some View {
        self.contentView
            .onChange(of: self.numberRaw) { newNumber in
                print("number: (self.number) -> (newNumber % 10)")
                self.number = newNumber % 10
            }
            .onChange(of: self.number) { newNumber in
                print("numberRaw: (self.numberRaw) -> (newNumber)")
                self.numberRaw = newNumber
            }
    }
    
    private var contentView: some View {
        VStack {
            Text("Number: (self.numberRaw)")
            TextField("Number", value: self.$numberRaw, formatter: NumberFormatter())
                .disableAutocorrection(true)
                .background(Color.gray)
        }
        .padding(.horizontal, 100)
    }
}
 

Если вы введете «99» и закроете клавиатуру, но «99» останется на экране, а журналы будут:

 number: 0 -> 9
numberRaw: 9 -> 9
number: 9 -> 9
 

Я добавил onSubmit, и «Текст» был обновлен до «9», но «Текстовое поле» осталось равным «99».

 .onSubmit {
  DispatchQueue.main.async {
    self.numberRaw = self.number
  }
}
 

параметры: MacBook Pro (13 дюймов, M1, 2020), macOS 11.6, версия XCode 13.0 (13A233), симулятор iOS 15.

Проблема проявляется при запуске приложения, вы сразу же вводите большое. Когда вы снова отредактируете его, это больше не будет проблемой.

Вот как это работает, но непонятно, почему само «Текстовое поле» не отслеживает изменения.

 struct ContentView: View {
    @State private var number: Int = 0
    @State private var numberRaw: Int = 0
    @State private var showTextField: Bool = false

    var body: some View {
        VStack {
            Text("NumberRaw: (self.numberRaw)")
            if self.showTextField {
                TextField("NumberRaw", value: self.$numberRaw, formatter: NumberFormatter())
                    .onSubmit {
                        self.showTextField = false
                    }
                    .disableAutocorrection(true)
                    .background(Color.gray)
            }
            else {
                Text("")
                    .onAppear {
                        self.numberRaw = self.number
                        self.showTextField = true
                    }
            }
        }
        .padding(.horizontal, 100)
    }
}
 

Комментарии:

1. кажется, это работает для меня на macos 12.01, xcode 13.1(RC), целевой ios 15 и macCatalyst. Text Шоу 4 , которое является 44444 % 10 = 4

2. @workingdog Мой «Текст» также обновлен, «Текстовое поле» не обновляется. Текстовое поле показывает 44444, но число == 4.

Ответ №1:

вы могли бы попробовать что-то подобное, чтобы достичь того, чего вы хотите:

 struct ContentView: View {
    @State private var txt = ""
    @State private var number: Int = 0
    
    var body: some View {
        VStack (spacing: 55) {
            Text("number: (number)")
            Text("txt: (txt)")
            TextField("Number", text: $txt)
                .onChange(of: txt) { val in
                    if let rem = Int(val) {
                        number = rem % 10
                        txt = String(number)
                    } else {
                        txt = ""
                        number = 0
                    }
                }
                .keyboardType(.numberPad)
                .disableAutocorrection(true)
                .background(Color.gray)
        }
        .padding(.horizontal, 100)
    }
}