我正在开发一个应用程序,该应用程序使用带有详细信息视图的传统边栏导航。我综合了这个应用程序来说明两个问题。
-
应用启动时,detail视图为空。如何通过编程方式在侧边栏中选择要在详细信息视图中显示的条目?
-
侧边栏允许滑动删除。如果所选的行(在详细视图中显示的行)被删除,它仍然显示在详细视图中。如何使用(例如)空视图更新详细视图?
下面是说明问题的应用程序的源代码:
import SwiftUI
class Model: ObservableObject {
var items = [Item("")]
static var loadData: Model {
let model = Model()
model.items = [Item("Books"), Item("Videos"), Item("Pics"), Item("Cars")]
return model
}
}
class Item: Identifiable, Hashable {
static func == (lhs: Item, rhs: Item) -> Bool {
lhs.name == rhs.name
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
let id = UUID()
@Published var name: String
init(_ name: String) {
self.name = name
}
}
@main
struct IBTSimulatorApp: App {
@StateObject var model = Model.loadData
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(model)
}
}
}
struct ContentView: View {
@EnvironmentObject var model: Model
var body: some View {
NavigationView {
List {
ForEach($model.items, id: .self) { $item in
NavigationLink(item.name, destination: Text(item.name))
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
}
private func addItem() {
withAnimation {
model.items.append(Item("New item ((model.items.count))"))
model.objectWillChange.send()
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
model.items.remove(atOffsets: offsets)
model.objectWillChange.send()
}
}
}
您可以使用带有标记和选择的NavigationLink
版本,并将活动选择保存在持久的AppStorage
变量中。
2。我希望您可以将选择设置为nil,但由于某些原因,这不起作用。但是您可以将它设置为侧边栏列表中的第一项。
一般来说,你应该让Item
成为一个结构体而不是一个类。只有发布的Model应该是一个类。
class Model: ObservableObject {
var items: [Item] = []
static var loadData: Model {
let model = Model()
model.items = [Item("Books"), Item("Videos"), Item("Pics"), Item("Cars")]
return model
}
}
struct Item: Identifiable { // Change from class to struct!
let id = UUID()
var name: String
init(_ name: String) {
self.name = name
}
}
struct ContentView: View {
@StateObject var model = Model.loadData
@AppStorage("selectemItem") var selected: String? // bind to persisted var here
var body: some View {
NavigationView {
List {
ForEach(model.items) { item in //no .id needed as Item is identifiable
NavigationLink(tag: item.id.uuidString, selection: $selected) { // use link with selection here
Text(item.name)
} label: {
Text(item.name)
}
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
Text("Nothing selected")
}
}
private func addItem() {
withAnimation {
model.objectWillChange.send()
model.items.append(Item("New item ((model.items.count))"))
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
// model.objectWillChange.send() // not necessary if Item is struct
self.selected = nil // for some reaseon this does not work
self.selected = model.items.first?.id.uuidString // selects first item
model.items.remove(atOffsets: offsets)
}
}
}