macosswiftui

SwiftUI TextField turn off continuous updates of backing value


I use SwiftUI TextField to edit a backing object property. As I type, the TextField invokes format parser and updates the backing property on every character I type, before I’ve completed the input. This intermediate input is uninteresting at best, and quite distracting at worst.

I’d like the TextField to accept any input until submit or loss of focus, and then apply format parser and update the backing property. Is there a way to do that in SwiftUI?

In Cocoa/Objective-C, I used NSBindingOption.continuouslyUpdatesValue set to false.

@State var text: String = "Hello"
var body: some View {
    Text(text) // This shows updated value on every input character.
    TextField("Text: ", text: $text)
        .continuouslyUpdatesValue(false) // I’d like to have something like this

Solution

  • You can write a TextField wrapper that uses its internal @State

    struct NonContinuousTextField: View {
        let title: LocalizedStringKey
        @Binding var text: String
        @State private var internalText = ""
        @State private var appeared = false
        
        init(_ title: LocalizedStringKey, text: Binding<String>) {
            self.title = title
            self._text = text
        }
        
        @FocusState var focused: Bool
        
        var body: some View {
            TextField(title, text: $internalText)
                .onAppear { // initialise internalText
                    if !appeared {
                        internalText = text
                        appeared = true
                    }
                }
                .focused($focused)
                .onSubmit {
                    text = internalText
                }
                .onChange(of: focused) { _, newValue in
                    if !newValue { // lose focus
                        text = internalText
                    }
                }
        }
    }