如何正确处理 macOS 上 NavigationView 中的选择?
How do I handle selection in NavigationView on macOS correctly?
我想根据侧边栏中的 selection 构建一个带有侧边栏和一些内容的普通 macOS 应用程序。
我有一个 MainView,其中包含一个 NavigationView
和一个 SidebarListStyle
。它包含一个 List
和一些 NavigationLink
。这些具有 select离子的结合。
我希望以下事情能起作用:
当我启动我的应用程序时,selection 的值被忽略。侧边栏中的项目没有突出显示,详细信息窗格中也没有内容。
当我在边栏中手动 select 一个项目时,应该可以通过 up/down 箭头键在项目之间导航。这不起作用,因为 selection / highlight 消失了。
当我更新 selection-binding 的值时,它应该突出显示列表中没有发生的项目。
这是我的示例实现:
enum DetailContent: Int, CaseIterable {
case first, second, third
}
extension DetailContent: Identifiable {
var id: Int { rawValue }
}
class NavigationRouter: ObservableObject {
@Published var selection: DetailContent?
}
struct DetailView: View {
@State var content: DetailContent
@EnvironmentObject var navigationRouter: NavigationRouter
var body: some View {
VStack {
Text("\(content.rawValue)")
Button(action: { self.navigationRouter.selection = DetailContent.allCases.randomElement()!}) {
Text("Take me anywhere")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct MainView: View {
@ObservedObject var navigationRouter = NavigationRouter()
@State var detailContent: DetailContent? = .first
var body: some View {
NavigationView {
List {
Section(header: Text("Section")) {
ForEach(DetailContent.allCases) { item in
NavigationLink(
destination: DetailView(content: item),
tag: item,
selection: self.$detailContent,
label: { Text("\(item.rawValue)") }
)
}
}
}
.frame(minWidth: 250, maxWidth: 350)
}
.environmentObject(navigationRouter)
.listStyle(SidebarListStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onReceive(navigationRouter.$selection) { output in
self.detailContent = output
}
}
}
EnvironmentObject
用于从 DetailView
内部传播更改。如果有更好的解决方案,我很高兴听到。
所以问题仍然存在:
发生这种情况我做错了什么?
我曾希望 Xcode 11.5 Beta 1 这会消失,但事实并非如此。
找到 tutorial from Apple 后,很明显您没有在 macOS 上使用 NavigiationLink
。相反,您绑定列表并将两个视图添加到 NavigationView
.
通过对 MainView
和 DetailView
的这些更新,我的示例完美运行:
struct DetailView: View {
@Binding var content: DetailContent?
@EnvironmentObject var navigationRouter: NavigationRouter
var body: some View {
VStack {
Text("\(content?.rawValue ?? -1)")
Button(action: { self.navigationRouter.selection = DetailContent.allCases.randomElement()!}) {
Text("Take me anywhere")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct MainView: View {
@ObservedObject var navigationRouter = NavigationRouter()
@State var detailContent: DetailContent?
var body: some View {
NavigationView {
List(selection: $detailContent) {
Section(header: Text("Section")) {
ForEach(DetailContent.allCases) { item in
Text("\(item.rawValue)")
.tag(item)
}
}
}
.frame(minWidth: 250, maxWidth: 350)
.listStyle(SidebarListStyle())
DetailView(content: $detailContent)
}
.environmentObject(navigationRouter)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onReceive(navigationRouter.$selection) { output in
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) {
self.detailContent = output
}
}
}
}
我想根据侧边栏中的 selection 构建一个带有侧边栏和一些内容的普通 macOS 应用程序。
我有一个 MainView,其中包含一个 NavigationView
和一个 SidebarListStyle
。它包含一个 List
和一些 NavigationLink
。这些具有 select离子的结合。
我希望以下事情能起作用:
当我启动我的应用程序时,selection 的值被忽略。侧边栏中的项目没有突出显示,详细信息窗格中也没有内容。
当我在边栏中手动 select 一个项目时,应该可以通过 up/down 箭头键在项目之间导航。这不起作用,因为 selection / highlight 消失了。
当我更新 selection-binding 的值时,它应该突出显示列表中没有发生的项目。
这是我的示例实现:
enum DetailContent: Int, CaseIterable {
case first, second, third
}
extension DetailContent: Identifiable {
var id: Int { rawValue }
}
class NavigationRouter: ObservableObject {
@Published var selection: DetailContent?
}
struct DetailView: View {
@State var content: DetailContent
@EnvironmentObject var navigationRouter: NavigationRouter
var body: some View {
VStack {
Text("\(content.rawValue)")
Button(action: { self.navigationRouter.selection = DetailContent.allCases.randomElement()!}) {
Text("Take me anywhere")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct MainView: View {
@ObservedObject var navigationRouter = NavigationRouter()
@State var detailContent: DetailContent? = .first
var body: some View {
NavigationView {
List {
Section(header: Text("Section")) {
ForEach(DetailContent.allCases) { item in
NavigationLink(
destination: DetailView(content: item),
tag: item,
selection: self.$detailContent,
label: { Text("\(item.rawValue)") }
)
}
}
}
.frame(minWidth: 250, maxWidth: 350)
}
.environmentObject(navigationRouter)
.listStyle(SidebarListStyle())
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onReceive(navigationRouter.$selection) { output in
self.detailContent = output
}
}
}
EnvironmentObject
用于从 DetailView
内部传播更改。如果有更好的解决方案,我很高兴听到。
所以问题仍然存在: 发生这种情况我做错了什么? 我曾希望 Xcode 11.5 Beta 1 这会消失,但事实并非如此。
找到 tutorial from Apple 后,很明显您没有在 macOS 上使用 NavigiationLink
。相反,您绑定列表并将两个视图添加到 NavigationView
.
通过对 MainView
和 DetailView
的这些更新,我的示例完美运行:
struct DetailView: View {
@Binding var content: DetailContent?
@EnvironmentObject var navigationRouter: NavigationRouter
var body: some View {
VStack {
Text("\(content?.rawValue ?? -1)")
Button(action: { self.navigationRouter.selection = DetailContent.allCases.randomElement()!}) {
Text("Take me anywhere")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
struct MainView: View {
@ObservedObject var navigationRouter = NavigationRouter()
@State var detailContent: DetailContent?
var body: some View {
NavigationView {
List(selection: $detailContent) {
Section(header: Text("Section")) {
ForEach(DetailContent.allCases) { item in
Text("\(item.rawValue)")
.tag(item)
}
}
}
.frame(minWidth: 250, maxWidth: 350)
.listStyle(SidebarListStyle())
DetailView(content: $detailContent)
}
.environmentObject(navigationRouter)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onReceive(navigationRouter.$selection) { output in
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) {
self.detailContent = output
}
}
}
}