Swiftui 中的默认导航 link
Default navigation link in Swiftui
我正在开发一个应用程序,该应用程序使用带有详细信息视图的传统侧边栏导航。我综合了这个应用程序来说明两个问题。
当应用程序启动时,详细视图是空的。如何以编程方式 select 侧边栏中的条目显示在详细信息视图中?
侧边栏允许滑动删除。如果 selected 行(显示在详细视图中的行)被删除,它仍然显示在详细视图中。例如,如何使用空视图更新详细视图?
以下是说明问题的应用源代码:
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()
}
}
}
对于 1. 您可以使用带有标签和选择的 NavigationLink
版本,并将活动选择保存在持久的 AppStorage
var.
中
对于 2。我希望您可以将选择设置为零,但由于某些原因这不起作用。但您可以将其设置为侧边栏列表中的第一项。
作为一般说明,您应该将 Item
设为结构而不是 class。只有发布的模型应该是 class.
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)
}
}
}
我正在开发一个应用程序,该应用程序使用带有详细信息视图的传统侧边栏导航。我综合了这个应用程序来说明两个问题。
当应用程序启动时,详细视图是空的。如何以编程方式 select 侧边栏中的条目显示在详细信息视图中?
侧边栏允许滑动删除。如果 selected 行(显示在详细视图中的行)被删除,它仍然显示在详细视图中。例如,如何使用空视图更新详细视图?
以下是说明问题的应用源代码:
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()
}
}
}
对于 1. 您可以使用带有标签和选择的 NavigationLink
版本,并将活动选择保存在持久的 AppStorage
var.
对于 2。我希望您可以将选择设置为零,但由于某些原因这不起作用。但您可以将其设置为侧边栏列表中的第一项。
作为一般说明,您应该将 Item
设为结构而不是 class。只有发布的模型应该是 class.
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)
}
}
}