How to edit selected item in list in SwiftUI

Issue #605

I use custom TextView in a master detail application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import SwiftUI

struct TextView: NSViewRepresentable {
@Binding var text: String

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

func makeNSView(context: Context) -> NSTextView {
let textView = NSTextView()
textView.delegate = context.coordinator
return textView
}

func updateNSView(_ nsView: NSTextView, context: Context) {
guard nsView.string != text else { return }
nsView.string = text
}

class Coordinator: NSObject, NSTextViewDelegate {
let parent: TextView

init(_ textView: TextView) {
self.parent = textView
}

func textDidChange(_ notification: Notification) {
guard let textView = notification.object as? NSTextView else { return }
self.parent.text = textView.string
}
}
}

No matter which item user selects, textView always updates the first one

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
struct Book {
var name: String = ""
}

class Store: ObservableObject {
@Published var books: [Book] = []
}

struct MainView: View {
@EnvironmentObject var store: Store

var body: some View {
List {
ForEach(store.books.enumerated().map({ $0 }), id: \.element.id) { index, book in {
Text(book.name)
.onTapGesture {
self.store.selectedIndex = index
}
}
}

HStack {
TextView($store.books[store.selectedIndex].name)
}
}
}

The fix is to pass selected object instead of using subscript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct MainView: View {
@EnvironmentObject var store: Store

var body: some View {
List {
ForEach(store.books.enumerated().map({ $0 }), id: \.element.id) { index, book in {
Text(book.name)
.onTapGesture {
self.store.selectedBook = self.store.books[index]
}
}
}

HStack {
TextView($store.selectedBook.name)
}
}
}

And we need to save selectedBook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Store: ObservableObject {
@Published var books: [Book] = []

@Published var selectedBook: Book = Book(name: "") {
didSet {
saveSelected()
}
}

func saveSelected() {
guard let index = self.books.firstIndex(where: { $0.id == selectedBook.id }) else {
return
}

books[index] = selectedBook
}
}

Read more


Updated at 2020-06-01 02:13:51

Comments