Search code examples
swiftswiftuiswiftui-navigationlink

Avoid Nested NavigationTabView


I'm struggling with something apparently simple. I have a view that arrives with a navigationLink since is not the primary view of my app. In this view i have some links that sends to this view but with different data's. I want to nest those links, but now i'm reciving the double tab View on top. How can I change this? I knwo that I need to toogle the Navigation bar on the second view, but my second view is actually the same view but with different data.

Here's the code

/// ContentView
struct MatchListView: View {
   var namespace: Namespace.ID
   @ObservedObject var dataViewModel = DataViewModel()
   @State private var selectedMatchID: Int?
   @State private var selectedDayIndex: Int = 0
   @State private var headerHeight: CGFloat = 0
   @State private var didFinishFirst = false

   var body: some View {
       ForEach(data.leagues, id: \.id) { league in
           VStack {
               leagueHeader(league: league)
               ForEach(league.matches, id: \.id) { match in
                   matchRow(match: match, namespace: namespace)
               }
            }
           .foregroundStyle(Color.textAccent)
           .background(Color.bgSecondaryAccent)
           .cornerRadius(10)
       }
   }
}

func matchRow(match: Match, namespace: Namespace.ID) -> some View {
   NavigationLink(destination: MatchDetailsView(namespace: namespace, matchID: match.id, homeTeamName: match.home.name, awayTeamName: match.away.name)) { 
       Text("go to match \(match.id)")
   }
}


/// MatchDetails View
struct MatchDetailsView: View {
   NavigationView {  
       List {
           ScrollView(showsIndicators: false) {
               HighlightsView(matchViewModel: matchViewModel)
               MOTMView(matchViewModel: matchViewModel)
               EventsView(matchViewModel: matchViewModel)
               MatchStats(matchViewModel: matchViewModel)
               MatchTopPlayers(matchViewModel: matchViewModel)                       
               TeamFormView(matchViewModel: matchViewModel)
           }        
       }
   }
   .toolbar {
       ShareLink(item: URL(string: "https://maykmayk.github.io/Balun/#/match-details/\(matchID)")!) {
           Label("", systemImage: "square.and.arrow.up")
       }
       Button {
           // action
       } label: {
           Image(systemName: "bell")
       }
       Button {
           // action
        } label: {
           Image(systemName: "star")
       }
   }
   .toolbarRole(.editor)
   .tint(Color(.textAccent))
}


/// TeamformView
struct TeamFormView: View {

   var body: some View {
       NavigationLink(destination: MatchDetailsView(namespace: namespace, matchID: getMatchID(from: match.linkToMatch ?? ""), homeTeamName: match.home?.name ?? "", awayTeamName: match.away?.name ?? "")) {
           Text(match.score ?? "")
               .foregroundColor(.white)
               .font(.system(size: 14, weight: .medium))
               .padding(.horizontal, 5)
               .padding(.vertical, 2.5)
               .background(
                   match.resultString == "W" ? Color.greenAccent :
                   match.resultString == "L" ? Color.redAccent :
                   match.resultString == "D" ? Color.gray.opacity(0.5) :
                   Color.black
               )
               .clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous))
       }
   }
}

My Preview: https://ibb.co/gRHcDSb What I want: https://ibb.co/W6ysFYn


Solution

  • Posting it as an answere here. The issue you are facing is due to nested NavigationView's. That's why you are seeing more then one navigation bar when navigating to a new screen. Tip: unless you are supporting iOS 15 or older, consider using NavigationStack.

    You can edit your code to resemble this:

    NavigationView {
        MatchListView(namespace: namespace)
    }
    

    MatchListView can stay as it was I guess:

    struct MatchListView: View {
       var namespace: Namespace.ID
       //@ObservedObject var dataViewModel = DataViewModel()
       @State private var selectedMatchID: Int?
       @State private var selectedDayIndex: Int = 0
       @State private var headerHeight: CGFloat = 0
       @State private var didFinishFirst = false
    
       var body: some View {
           ForEach(["Leage 1", "League 2"], id: \.self) { league in
               VStack {
                   
                   ForEach(["Match 1", "Match 2"], id: \.self) { match in
                       NavigationLink(destination: MatchDetailsView()) {
                              Text("go to match ID")
                        }
                   }
                }
               .foregroundStyle(.black)
               .background(.fill)
               .cornerRadius(10)
           }
       }
    }
    

    Remove the other NavigationView from here:

    struct MatchDetailsView: View {
        
        var body: some View {
            
            /// Remove this NavigationView and others if parents views already have one
            //NavigationView {
                List {
                    ScrollView(showsIndicators: false) {
                        //               HighlightsView(matchViewModel: matchViewModel)
                        //               MOTMView(matchViewModel: matchViewModel)
                        //               EventsView(matchViewModel: matchViewModel)
                        //               MatchStats(matchViewModel: matchViewModel)
                        //               MatchTopPlayers(matchViewModel: matchViewModel)
                        TeamFormView()
                    }
                }
                
                .toolbar {
                    
                }
                .toolbarRole(.editor)
                .tint(.accentColor)
            //}
        }
        
    }
    

    I hope this has worked well for you and the explaination was clear!