Ganesh Kumar M V
Ganesh Kumar M V

Reputation: 31

SwiftUI List row is selected instead of focusing the TextField

Problem

Reproducible Example

struct DemoView: View {
    @ObservedObject var model: DemoModel

    var body: some View {
        List(selection: self.$model.selectedRows) {
            DisclosureGroup(isExpanded: self.$model.isExpanded, content: {
                ForEach(self.model.models) { rowModel in
                    RowView(rowModel: rowModel)
                        .contentShape(Rectangle())
                        .swipeActions {
                            Button("Swipe") {
                            }
                        }
                }
                .onMove { fromIndices, toIndex in
                    self.model.models.move(fromOffsets: fromIndices, toOffset: toIndex)
                }
            }, label: {
                HStack(alignment: .center) {
                    Text("Title")
                    Spacer()
                    Button("Add row", systemImage: "plus") {
                        let rowModel = RowModel()
                        self.model.models.append(rowModel)
                    }
                }
            })
        }
    }
}

class DemoModel: ObservableObject {
    @Published var models: [RowModel]
    @Published var isExpanded: Bool
    @Published var selectedRows: Set<UUID>

    init() {
        let one = RowModel()
        let two = RowModel()
        self.models = [one, two]
        self.isExpanded = true
        self.selectedRows = Set()
    }
}

enum CustomFocusState {
    case textFieldOne, textFieldTwo
}

struct RowView: View {
    @ObservedObject var rowModel: RowModel
    @FocusState var focuseState: CustomFocusState?

    var body: some View {
        HStack {
            TextField("Enter text", text: self.$rowModel.text)
                .textFieldStyle(.roundedBorder)
                .padding()
                .focusable()
                .focused($focuseState, equals: .textFieldOne)
                .onTapGesture {
                    self.focuseState = .textFieldOne
                    print("tapped textFieldOne")
                }
            TextField("Enter text", text: self.$rowModel.text2)
                .textFieldStyle(.roundedBorder)
                .padding()
                .focusable()
                .focused($focuseState, equals: .textFieldTwo)
                .onTapGesture {
                    self.focuseState = .textFieldTwo
                    print("tapped textFieldTwo")
                }
        }
    }
}

class RowModel: ObservableObject, Identifiable {
    @Published var text: String
    @Published var text2: String
    var id: UUID

    init() {
        self.text = ""
        self.text2 = ""
        self.id = UUID()
    }
}

extension RowModel: Hashable {
    static func == (lhs: RowModel, rhs: RowModel) -> Bool {
        lhs.id == rhs.id
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(self.id)
    }
}

Current behaviour

Expected behaviour

EDIT

Upvotes: 3

Views: 157

Answers (2)

malhal
malhal

Reputation: 30746

Change RowModel to a struct. It doesn't make sense for classes to be identified by id, since they already are identified by their pointer, so change it to a struct. @Published needs to be an array of model structs to work anyway.

Also, remove selection from the model store object. If you think about it you might want the model data to be presented in different ways all which might need their own selection so selection should be @State instead.

Upvotes: 0

Ashesh Patel
Ashesh Patel

Reputation: 1

Try removing .focusable() from the text field.

Upvotes: -2

Related Questions