如何在 NavigationLink 之间导航,同时保留一部分 main window 在 SwiftUI 中保持不变
How to navigate between NavigationLink while leave a part of main window stay the same in SwiftUI
我想在 NavigationView
中的不同 NavigationLink
之间导航,而主要 window 的某些部分保持不变。例如,我想制作一个音乐应用程序,我想让播放控制器始终在顶部,同时我可以使用 window 的其余部分显示不同的导航内容(歌曲页面、艺术家页面...)。
如下图所示,我希望红色部分一直存在,蓝色部分变化。
Navigation Example Picture
我的代码如下所示,但无法正常工作。单击边栏上的任何 NavigationLink
时 AlwaysStayView()
消失。那么,我该如何更正它或者是否有任何解决方案(更喜欢 SwiftUI,但像 UIKit 这样的框架也可以)。我将不胜感激。
NavigationView {
List {
NavigationLink { DiscoverView() }
label: { Label("Discover", systemImage: "magnifyingglass") }
NavigationLink { SongsView() }
label: { Label("Songs", systemImage: "music.note") }
NavigationLink { ArtistsView() }
label: { Label("Artists", systemImage: "music.mic") }
}
}
.listStyle(SidebarListStyle())
VStack {
AlwaysStayView()
SongsView()
}
}
在这种情况下,默认 详细信息视图和导航详细信息视图应该相同,但可以在导航中将更新的内容注入其中 link。
这是一个演示。使用 Xcode 13.3 / iPadOS 15.4
测试
struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink { DetailsView { DiscoverView() } }
label: { Label("Discover", systemImage: "magnifyingglass") }
NavigationLink { DetailsView { SongsView() } }
label: { Label("Songs", systemImage: "music.note") }
NavigationLink { DetailsView { ArtistsView() } }
label: { Label("Artists", systemImage: "music.mic") }
}
.navigationBarHidden(true)
.listStyle(SidebarListStyle())
DetailsView { SongsView() } // << here default !!
}
}
}
struct DetailsView<V: View>: View {
@ViewBuilder var content: () -> V // << injected via builder !!
var body: some View {
VStack(spacing: 0) {
AlwaysStayView()
content() // << changed part here !!
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.navigationBarHidden(true)
}
}
侧边栏的 NavigationLink
始终交换整个右侧屏幕区域。所以你必须把你的 AlwaysStayView 放在导航链接里——在每一个里。在顶层或在各自的详细视图中。这是一个例子:
struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Discover", color: .blue) }
label: { Label("Discover", systemImage: "magnifyingglass") }
NavigationLink {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Songs", color: .teal) }
label: { Label("Songs", systemImage: "music.note") }
NavigationLink {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Artists", color: .mint) }
label: { Label("Artists", systemImage: "music.mic") }
}
.listStyle(.sidebar)
// Standard view if no item is lelected
VStack {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Songs", color: .teal)
}
}
.toolbar {
ToolbarItem(placement: .principal) {
Text("Toolbar")
}
}
}
}
struct DetailView: View {
let title: String
let color: Color
var body: some View {
Text(title).font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(color)
}
}
我想在 NavigationView
中的不同 NavigationLink
之间导航,而主要 window 的某些部分保持不变。例如,我想制作一个音乐应用程序,我想让播放控制器始终在顶部,同时我可以使用 window 的其余部分显示不同的导航内容(歌曲页面、艺术家页面...)。
如下图所示,我希望红色部分一直存在,蓝色部分变化。
Navigation Example Picture
我的代码如下所示,但无法正常工作。单击边栏上的任何 NavigationLink
时 AlwaysStayView()
消失。那么,我该如何更正它或者是否有任何解决方案(更喜欢 SwiftUI,但像 UIKit 这样的框架也可以)。我将不胜感激。
NavigationView {
List {
NavigationLink { DiscoverView() }
label: { Label("Discover", systemImage: "magnifyingglass") }
NavigationLink { SongsView() }
label: { Label("Songs", systemImage: "music.note") }
NavigationLink { ArtistsView() }
label: { Label("Artists", systemImage: "music.mic") }
}
}
.listStyle(SidebarListStyle())
VStack {
AlwaysStayView()
SongsView()
}
}
在这种情况下,默认 详细信息视图和导航详细信息视图应该相同,但可以在导航中将更新的内容注入其中 link。
这是一个演示。使用 Xcode 13.3 / iPadOS 15.4
测试struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink { DetailsView { DiscoverView() } }
label: { Label("Discover", systemImage: "magnifyingglass") }
NavigationLink { DetailsView { SongsView() } }
label: { Label("Songs", systemImage: "music.note") }
NavigationLink { DetailsView { ArtistsView() } }
label: { Label("Artists", systemImage: "music.mic") }
}
.navigationBarHidden(true)
.listStyle(SidebarListStyle())
DetailsView { SongsView() } // << here default !!
}
}
}
struct DetailsView<V: View>: View {
@ViewBuilder var content: () -> V // << injected via builder !!
var body: some View {
VStack(spacing: 0) {
AlwaysStayView()
content() // << changed part here !!
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.navigationBarHidden(true)
}
}
侧边栏的 NavigationLink
始终交换整个右侧屏幕区域。所以你必须把你的 AlwaysStayView 放在导航链接里——在每一个里。在顶层或在各自的详细视图中。这是一个例子:
struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Discover", color: .blue) }
label: { Label("Discover", systemImage: "magnifyingglass") }
NavigationLink {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Songs", color: .teal) }
label: { Label("Songs", systemImage: "music.note") }
NavigationLink {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Artists", color: .mint) }
label: { Label("Artists", systemImage: "music.mic") }
}
.listStyle(.sidebar)
// Standard view if no item is lelected
VStack {
DetailView(title: "Always stay", color: .red).frame(height: 100)
DetailView(title: "Songs", color: .teal)
}
}
.toolbar {
ToolbarItem(placement: .principal) {
Text("Toolbar")
}
}
}
}
struct DetailView: View {
let title: String
let color: Color
var body: some View {
Text(title).font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(color)
}
}