Select 列表中的第一项并在应用程序启动时突出显示它

Select the first item on a list and highlight it when the application launches

当该应用首次在 macOS (Big Sur) 中启动时,它会使用用户保存的项目填充一个列表。当用户单击该列表中的项目时,将打开第二个视图,显示该项目的内容。 有没有办法 select 该列表中的第一项,就像用户单击它一样,并在应用程序启动时显示第二个视图?此外,如果我删除了列表中的项目,我将无法返回 select 列表中的第一项并显示该项目的第二个视图,或者如果我创建新项目,同样适用,不能' tselect它。

我试过在此处查看答案,例如 , and ,并查看并尝试了来自不同地方的代码,但我无法使其正常工作。

所以,使用我的 上回答的代码,这是基本应用程序的样子:

struct NoteItem: Codable, Hashable, Identifiable {
    let id: Int
    var text: String
    var date = Date()
    var dateText: String {
        dateFormatter.dateFormat = "EEEE, MMM d yyyy, h:mm a"
        return dateFormatter.string(from: date)
    }
    var tags: [String] = []
}

final class DataModel: ObservableObject {
    @AppStorage("notes") public var notes: [NoteItem] = []
}


struct AllNotes: View {
    
    @EnvironmentObject private var data: DataModel
    
    @State var noteText: String = ""
    
    var body: some View {
        NavigationView {
            List(data.notes) { note in
                NavigationLink(destination: NoteView(note: note)) {
                    VStack(alignment: .leading) {
                        Text(note.text.components(separatedBy: NSCharacterSet.newlines).first!)
                        Text(note.dateText).font(.body).fontWeight(.light)
                    }
                    .padding(.vertical, 8)
                }
            }
            .listStyle(InsetListStyle())
            
            Text("Select a note...")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
        .navigationTitle("A title")
        .toolbar {
            ToolbarItem(placement: .navigation) {
                Button(action: {
                    data.notes.append(NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []))
                }) {
                    Image(systemName: "square.and.pencil")
                }
            }
        }
    }
}

struct NoteView: View {
    
    @EnvironmentObject private var data: DataModel
    var note: NoteItem
    
    @State var text: String = ""
    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                TextEditor(text: $text).padding().font(.body)
                    .onChange(of: text, perform: { value in
                        guard let index =     data.notes.firstIndex(of: note) else { return }
                        data.notes[index].text = value
                    })
                Spacer()
            }
            Spacer()
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.white)
        .onAppear() {
            print(data.notes.count)
        }
    }
}

我尝试在 AllNotes 中添加 @State var selection: Int?,然后将列表更改为

List(data.notes, selection: $selection)

并尝试使用它,但我无法将它变成 select 任何东西。 抱歉,SwiftUI 新手,正在尝试学习。

谢谢!

你很接近。 Table 使用 selection 查看更多关于 selecting table 视图中的项目,但您需要 select NavigationLink 才能打开

还有另一个初始化程序可以完全满足您的需要。您向 selection 传递当前 selected 项目。给 tag 传递当前列表项,如果它与 selection 相同,NavigationLink 将打开

你还需要存储 selectedNoteId 而不是 selectedNote,因为这个值在你更新笔记属性后不会改变

这里我将 selectedNoteId 设置为 onAppear 中的第一项。你不得不在这里使用 DispatchQueue.main.async hack,可能是一个 NavigationLink bug

要在项目被删除时跟踪项目,您可以使用 onChange 修饰符,每次传递的值与之前的渲染不同时都会调用此方法

struct AllNotes: View {
    
    @EnvironmentObject private var data: DataModel
    
    @State var noteText: String = ""
    @State var selectedNoteId: UUID?
    
    var body: some View {
        NavigationView {
            List(data.notes) { note in
                NavigationLink(
                    destination: NoteView(note: note),
                    tag: note.id,
                    selection: $selectedNoteId
                ) {
                    VStack(alignment: .leading) {
                        Text(note.text.components(separatedBy: NSCharacterSet.newlines).first!)
                        Text(note.dateText).font(.body).fontWeight(.light)
                    }
                    .padding(.vertical, 8)
                }
            }
            .listStyle(InsetListStyle())
        }
        .navigationTitle("A title")
        .toolbar {
            ToolbarItem(placement: .navigation) {
                Button(action: {
                    data.notes.append(NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []))
                }) {
                    Image(systemName: "square.and.pencil")
                }
            }
        }
        .onAppear {
            DispatchQueue.main.async {
                selectedNoteId = data.notes.first?.id
            }
        }
        .onChange(of: data.notes) { notes in
            if selectedNoteId == nil || !notes.contains(where: { [=10=].id == selectedNoteId }) {
                selectedNoteId = data.notes.first?.id

            }
        }
    }
}

不确定 @AppStorage("notes") 有什么用,它应该不起作用,因为此注释仅适用于简单类型。如果您想将项目存储在用户默认值中,则必须手动完成。

删除它后,您丢失了 @Published,这就是我的情况下它没有更新的原因。如果 AppStorage 可以工作,它可能没有 @Published

final class DataModel: ObservableObject {
    
    @Published
    public var notes: [NoteItem] = [
        NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []),
        NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []),
        NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []),
        NoteItem(id: UUID(), text: "New Note", date: Date(), tags: []),
    ]
}