Home > Software design >  How to navigate between NavigationLink while leave a part of main window stay the same in SwiftUI
How to navigate between NavigationLink while leave a part of main window stay the same in SwiftUI

Time:05-07

I would like to navigate between different NavigationLinks in NavigationView while some part of the main window stay the same. For example, I want to make a music app and I want to let the play controller always on top, while I can display different navigation contents (songs page, artists page...) using the rest of the window.

Like what's showed in the picture below, I want to keep the red part always there while the blue part changes.

demo

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)
    }
}

backup

CodePudding user response:

The NavigationLink from sidebar always exchanges the whole right screen area. So you would have to put your AlwaysStayView inside the navigation links – in each. Either on top level or inside the respective detail views. Here is one example:

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)
    }
}
  • Related