SwiftUI:Select NavigationView 中的 NavigationLink / 带有 SidebarListStyle 的列表
SwiftUI: Select NavigationLink in a NavigationView / List with SidebarListStyle
我想在 NavigationView
/ List
中以编程方式 select 特定 NavigationLink
。
以下代码在纵向或横向模式的 iPhone 上都能正常工作 == 在列表除了其目标视图之外不是永久可见的情况下。
代码:
struct ContentView: View {
private let listItems = [ListItem(), ListItem(), ListItem()]
@State var selection: Int? = 0
var body: some View {
NavigationView {
List(listItems.indices) {
index in
let item = listItems[index]
let isSelected = (selection ?? -1) == index
NavigationLink(destination: Text("Destination \(index)"),
tag: index,
selection: $selection) {
Text("\(item.name) \(index) \(isSelected ? "selected" : "")")
}
}
}
.listStyle(SidebarListStyle())
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
selection = 2
})
})
}
}
struct ListItem: Identifiable {
var id = UUID()
var name: String = "Some Item"
}
但它在 iPad 的横屏模式下失败了:虽然导航本身有效(目的地显示正确),NavigationLink
仍然未selected。
→ 我怎样才能 select NavigationLink 在 iPad 上 select 的显示方式?
这是可能的方法。这个想法是通过视图模型以编程方式激活导航 link,但将 model-level 选择和呈现(由 link 拥有)选择分开。
使用 Xcode 12b3 / iOS+iPadOS 14 进行测试。
class SelectionViewModel: ObservableObject {
var currentRow: Int = -1 {
didSet {
self.selection = currentRow
}
}
@Published var selection: Int? = nil
}
struct SidebarContentView: View {
@StateObject var vm = SelectionViewModel()
private let listItems = [ListItem(), ListItem(), ListItem()]
var body: some View {
NavigationView {
List(listItems.indices) {
index in
let item = listItems[index]
let isSelected = vm.currentRow == index
Button("\(item.name) \(index) \(isSelected ? "selected" : "")") { vm.currentRow = index }
.background (
NavigationLink(destination: Text("Destination \(index) selected: \(vm.currentRow)"),
tag: index,
selection: $vm.selection) {
EmptyView()
}.hidden()
)
}
}
.listStyle(SidebarListStyle())
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
vm.currentRow = 2
})
})
}
}
我想在 NavigationView
/ List
中以编程方式 select 特定 NavigationLink
。
以下代码在纵向或横向模式的 iPhone 上都能正常工作 == 在列表除了其目标视图之外不是永久可见的情况下。
代码:
struct ContentView: View {
private let listItems = [ListItem(), ListItem(), ListItem()]
@State var selection: Int? = 0
var body: some View {
NavigationView {
List(listItems.indices) {
index in
let item = listItems[index]
let isSelected = (selection ?? -1) == index
NavigationLink(destination: Text("Destination \(index)"),
tag: index,
selection: $selection) {
Text("\(item.name) \(index) \(isSelected ? "selected" : "")")
}
}
}
.listStyle(SidebarListStyle())
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
selection = 2
})
})
}
}
struct ListItem: Identifiable {
var id = UUID()
var name: String = "Some Item"
}
但它在 iPad 的横屏模式下失败了:虽然导航本身有效(目的地显示正确),NavigationLink
仍然未selected。
→ 我怎样才能 select NavigationLink 在 iPad 上 select 的显示方式?
这是可能的方法。这个想法是通过视图模型以编程方式激活导航 link,但将 model-level 选择和呈现(由 link 拥有)选择分开。
使用 Xcode 12b3 / iOS+iPadOS 14 进行测试。
class SelectionViewModel: ObservableObject {
var currentRow: Int = -1 {
didSet {
self.selection = currentRow
}
}
@Published var selection: Int? = nil
}
struct SidebarContentView: View {
@StateObject var vm = SelectionViewModel()
private let listItems = [ListItem(), ListItem(), ListItem()]
var body: some View {
NavigationView {
List(listItems.indices) {
index in
let item = listItems[index]
let isSelected = vm.currentRow == index
Button("\(item.name) \(index) \(isSelected ? "selected" : "")") { vm.currentRow = index }
.background (
NavigationLink(destination: Text("Destination \(index) selected: \(vm.currentRow)"),
tag: index,
selection: $vm.selection) {
EmptyView()
}.hidden()
)
}
}
.listStyle(SidebarListStyle())
.onAppear(perform: {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
vm.currentRow = 2
})
})
}
}