navigationscrollviewswiftuinavigationlink

SwiftUI Scrollview Breaks NavigationLink Behavior


I'm having a problem where I toggle a setting in a details view, and immediately after the toggle of the setting, the navigation pops back to the main screen. This only happens when using a ScrollView instead of a List on the main screen. Does anyone have a solution or know if this is bug that will be fixed? I waited for Xcode 11 Beta 7 today, but that has not fixed the issue.

Current Behavior With ScrollView:

  1. Click on a row to be taken to details screen
  2. Click on the start to toggle the favorite setting
  3. Immediately jumps back to the main screen

Expected Behavior With ScrollView (Current Behavior With List):

  1. Click on a row to be taken to details screen
  2. Click on the start to toggle the favorite setting
  3. Stay on the details screen and be able to toggle the favorite setting over and over
  4. Click on the back button to be taken back to the main screen

    import SwiftUI
    import Combine
    
    struct Sport: Identifiable{
        var id = UUID()
        var name : String
        var isFavorite = false
        var school : String
    }
    
    final class UserData: ObservableObject  {
        @Published var sportsData =
            [
                Sport(name: "soccer", isFavorite: false, school: "WPI"),
                Sport(name: "tennis", isFavorite: true, school: "WPI"),
                Sport(name: "swimming", isFavorite: true, school: "WPI"),
                Sport(name: "running", isFavorite: true, school: "RIT"),
        ]
    }
    
    struct ContentView: View {
        @EnvironmentObject var userData: UserData
    
        var body: some View {
            NavigationView{
                List{
                    ForEach(userData.sportsData){ sport in
                        if sport.isFavorite{
                            NavigationLink(destination:
                                DetailsView(sport: sport)
                            ){
                                HStack {
                                    Text(sport.name)
                                    Spacer()
                                    Image(systemName: "star.fill")
                                        .foregroundColor(sport.isFavorite ? .yellow : .gray)
                                }
                            }
    
                        }
    
                    }
                }
            }.navigationBarTitle("Settings")
        }
    }
    
    struct DetailsView: View {
        @EnvironmentObject var userData: UserData
        var sport: Sport
        var sportIndex: Int {
            userData.sportsData.firstIndex(where: { $0.id == sport.id })!
        }
    
        var body: some View {
            ZStack {
                Text(sport.name).offset(x: 0, y: 100)
                Button(action: {
                    self.userData.sportsData[self.sportIndex].isFavorite.toggle()
                    print(self.sport.isFavorite)
                }) {
                    Image(systemName: "star.fill")
                        .foregroundColor(self.userData.sportsData[self.sportIndex].isFavorite ? .yellow : .gray)
                }
            }.padding(.horizontal)
        }
    }
    
    
    
    #if DEBUG
    struct Testing_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
                .environmentObject(UserData())
        }
    }
    #endif
    

Solution

  • one thing that could be affecting this is it looks like you are destroying the original NavigationLink in the forEach if favorite == false.

    So if that is the NavigationLink we came in on to the Detail, then it's disappearing when favorite is set to false. Is that what you are intending to do?