我有一个 NavigationSplitView ,带有 Sidebar 和 Detail 视图。从侧边栏中选择项目时,详细信息视图会更新以显示所选内容。到目前为止,这一切在 iPhone 和 iPad 上都运行良好。
但是,在 iPhone 上,当返回侧边栏视图选择其他内容时,之前选择的项目将被设置为 nil。
在 iPad 上,它不会将之前选择的项目设置为 nil,即使您隐藏并显示侧边栏,它仍然会记住之前选择的条目。
我也尝试过 iPhone 模拟器和物理设备。
要重现该问题,请参阅下面的小(完整)代码。在模拟器或物理设备上运行它。从侧边栏中选择一个条目,将显示/更新详细信息以显示所选内容。返回到侧边栏视图,您可以看到大约半秒钟之前选择的项目仍然处于选中状态,然后它被设置为 nil。
返回侧边栏视图时,为什么 iPhone 上的选择会重置为零?
import SwiftUI
struct ContentView: View {
@State private var selection: String?
var body: some View {
NavigationSplitView {
SidebarView(selection: $selection)
} detail: {
DetailView(selection: $selection)
}
}
}
struct SidebarView: View {
@Binding var selection: String?
let people = ["Finn", "Leia", "Luke", "Rey"]
var body: some View {
List(people, id: \.self, selection: $selection) { person in
Text(person)
}
Text("selection = \(String(describing: selection))")
}
}
struct DetailView: View {
@Binding var selection: String?
var body: some View {
Text("selectedItem = \(String(describing: selection))")
}
}
#Preview {
ContentView()
}
参见下面的 GIF。注意屏幕底部的侧边栏。返回侧边栏时,您会看到它仍然显示先前选择的项目,时间很短,大约半秒左右。然后它就被清零了。
只需将
@State
设置为非可选即可。然后使用其初始化程序之一将其转换为 Binding<String?>
,然后将其传递给 selection:
struct ContentView: View {
@State private var selection: String = "Finn"
var body: some View {
NavigationSplitView {
SidebarView(selection: $selection)
} detail: {
DetailView(selection: $selection)
}
}
}
struct SidebarView: View {
@Binding var selection: String
let people = ["Finn", "Leia", "Luke", "Rey"]
var body: some View {
// note the selection parameter
List(people, id: \.self, selection: Binding($selection)) { person in
Text(person)
// if you want to indicate the previously selected person more clearly
.listRowBackground(selection == person ? Color.gray : nil)
}
Text("selection = \(String(describing: selection))")
}
}
struct DetailView: View {
@Binding var selection: String
var body: some View {
Text("selectedItem = \(String(describing: selection))")
}
}
这迫使您做出初步选择。如果您不希望这样,您可以在
@State
或 SidebarView
中添加新的 ContentView
。
struct SidebarView: View {
@Binding var selection: String?
@State private var visitedPerson: String?
let people = ["Finn", "Leia", "Luke", "Rey"]
var body: some View {
Group {
List(people, id: \.self, selection: $selection) { person in
Text(person)
// if you want to indicate the previously selected person more clearly
.listRowBackground(visitedPerson == person ? Color.gray : nil)
}
Text("selection = \(String(describing: visitedPerson))")
}
.onChange(of: selection) { oldValue, newValue in
if let newValue {
visitedPerson = newValue
}
}
}
}
也就是说,“强制取消选择”行为与 iOS 在其他地方的行为方式是一致的。当视图被推到
List
顶部然后弹出时,List
将不会保留其选择。
参见示例:
struct ContentView: View {
@State private var items = ["One", "Two", "Three"]
@State private var selected: String?
var body: some View {
NavigationStack {
List(items, id: \.self, selection: $selected) { item in
Text(item)
}
.toolbar {
NavigationLink("Navigate") {
Text("Destination")
}
}
}
}
}