Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Editable TextField in SwiftUI List

Tags:

swiftui

appkit

UPDATE: 14 months later, there is this intriguing note in the AppKit release notes:

A TextField that you are editing inside a selected List row now has correct text foreground colors. (68545878)

Now when placing a TextField in a List, the TextField becomes focused on click the very first time it is selected, but subsequent editing attempts fail: the List row is selected but the TextField does not gain focus.

O/P:

In a beta6 SwiftUI macOS (not iOS) app, I need to have a List with editable text fields, but the TextFields in the list are not editable. It works fine if I swap out List for Form (or just VStack), but I need it working with a List. Is there some trick to tell the list to make the fields editable?

import SwiftUI

struct ContentView: View {
    @State var stringField: String = ""

    var body: some View {
        List { // works if this is VStack or Form
            Section(header: Text("Form Header"), footer: Text("Form Footer")) {
                TextField("Line 1", text: $stringField).environment(\.isEnabled, true)
                TextField("Line 2", text: $stringField)
                TextField("Line 3", text: $stringField)
                TextField("Line 4", text: $stringField)
                TextField("Line 5", text: $stringField)
            }
        }
    }
}
like image 663
marcprux Avatar asked Aug 20 '19 14:08

marcprux


People also ask

How do I make an editable list in SwiftUI?

If you have configured a SwiftUI list view to support deletion or editing of its items, you can allow the user to toggle editing mode for your list view by adding an EditButton somewhere. When that is run, you'll find you can tap the edit button to enable or disable editing mode for the items in the list.

How do you make a TextField not editable in SwiftUI?

Set the Boolean variable to false, which enables editing in the text field. When someone taps the Done button, isEditing becomes false. Set the Boolean variable to true, which disables editing in the text field.


2 Answers

The following code is only an experiment to understand the character of List in SwiftUI and show an alternative. What I understand from observing the output from various combinations is that, List View's style is structured in a way to override the default behaviors of underlying View to become Selectable. This means that TextField does absolutely different. TextField is an focusable element where we can type. This focusing variable is not wired in to List View to work together. Hence, List override default focusable. Hence it is not possible to create List with TextView. But if you need, next best option is ScrollView instead of List and do the styling explicitly. Check the following code and both ways.

import SwiftUI

struct ContentView: View {
    @State private var arr = ["1","2","3"]
    var body: some View {
        HStack {
            VStack {
                List {
                    ForEach(self.arr.indices, id:\.self) {
                        TextField("", text: self.$arr[$0])
                    }
                }
            }
            .frame(minWidth: 150, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
            VStack {
                ScrollView {
                    ForEach(self.arr.indices, id:\.self) {
                        TextField("", text: self.$arr[$0])
                        .textFieldStyle(PlainTextFieldStyle())
                        .padding(2)
                    }
                }
                .padding(.leading, 5)
                .padding(3)
            }
            .background(Color(NSColor.alternatingContentBackgroundColors[0]))
            .frame(minWidth: 150, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
        }
    }
}

extension NSTextField {
    open override var focusRingType: NSFocusRingType {
        get { .none }
        set { }
    }
}
like image 145
NikzJon Avatar answered Sep 21 '22 20:09

NikzJon


Bug Report

I updated the project to target a MacOS app and found the bug you are reporting. I've updated Apple with this feedback because it indeed does seem to be a bug (Welcome to Beta).

FB7174245 - SwiftUI Textfields embedded in a List are not editable when target is macOS

Update

So what's the point of all the focus on state and binding below? One variable should be bound to a single control. Here is a working example. I'll leave up the older answer as it carries the example forward with a full app saving and retrieving data to/from CoreData.

import SwiftUI

struct ContentView: View {
    @State var field1: String = ""
    @State var field2: String = ""
    @State var field3: String = ""
    @State var field4: String = ""
    @State var field5: String = ""

    var body: some View {
        List { // works if this is VStack or Form
            Section(header: Text("Form Header"), footer: Text("Form Footer")) {
                TextField("Line 1", text: $field1).environment(\.isEnabled, true)
                TextField("Line 2", text: $field2)
                TextField("Line 3", text: $field3)
                TextField("Line 4", text: $field4)
                TextField("Line 5", text: $field5)
            }
        }
    }
}

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

BTW - This works on Xcode Beta (11M392r) with MacOS Catalina - 10.15 Beta (19A546d).

Sample Project

Check out this sample that includes an editable Textfield that writes to CoreData, which I am building on Github.

Take a look at the difference between @State and @Binding so that you can manipulate data from outside of the content view. (60-sec video)

struct ContentView: View {
    // 1.
    @State var name: String = ""
    var body: some View {
        VStack {
            // 2.
            TextField(" Enter some text", text: $name)
                .border(Color.black)
            Text("Text entered:")
            // 3.
            Text("\(name)")
        }
        .padding()
        .font(.title)
    }
}

source

Check out the following answer for the appropriate use-case of @State (SO Answer)

like image 27
Tommie C. Avatar answered Sep 19 '22 20:09

Tommie C.