Conditional Navigation Links in Parent View Forcing Navigation From Child View back to Parent View When Condition is No Longer Met

import SwiftUI

struct ConditionalNavigationParentView: View {
    @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
    @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
    
    var body: some View {

        NavigationView {
            
            // iPhone Portrait
            if horizontalSizeClass == .compact && verticalSizeClass == .regular {
                
                VStack {
                    
                    Text("This is the Parent View.")
                        .foregroundColor(Color.black)
                        .font(.headline)
                    
                    NavigationLink(destination: ConditionalNavigationChildView()) {
                        
                        Text("Navigate to Child View.")
                            .font(.body)
                    }
                }
            }
            
            // iPhone Landscape
            if verticalSizeClass == .compact {
                
                HStack {
                    
                    Text("This is the Parent View.")
                        .foregroundColor(Color.black)
                        .font(.headline)
                    
                    NavigationLink(destination: ConditionalNavigationChildView()) {
                        
                        Text("Navigate to Child View.")
                            .font(.body)
                    }
                }
            }
        }
    }
}

struct ConditionalNavigationChildView: View {
    
    var body: some View {
        
        Text("This is the Child View.")
            .font(.headline)
    }
}

In the above code, we have a Parent View and a Child View. The parent view holds a conditional title and navigation link. The child view holds a title. When you navigate to the child view, navigation works fine. However, once the condition that holds the navigation link in the parent view is no longer met (by rotating your device from portrait to landscape), the connection keeping the child and parent views navigatable breaks, and forces navigation back to the parent view. This appears to be because SwiftUI as it is now needs to redraw the components from the parent view. With the example above, one solution would be to make only the text condtional, and have the navgation link be held in both a vstack and hstack simultaneously, like this:


import SwiftUI

struct ConditionalNavigationParentView: View {
    @Environment(\.verticalSizeClass) var verticalSizeClass: UserInterfaceSizeClass?
    @Environment(\.horizontalSizeClass) var horizontalSizeClass: UserInterfaceSizeClass?
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                
                // iPhone Portrait
                if horizontalSizeClass == .compact && verticalSizeClass == .regular {
                    
                    Text("This is the Parent View.")
                        .foregroundColor(Color.black)
                        .font(.headline)
                }
                
                HStack {
                    
                    // iPhone Landscape
                    if verticalSizeClass == .compact {
                        
                        Text("This is the Parent View.")
                            .foregroundColor(Color.black)
                            .font(.headline)
                    }
                    
                    NavigationLink(destination: ConditionalNavigationChildView()) {
                        
                        Text("Navigate to Child View.")
                            .font(.body)
                    }
                }
            }
        }
    }
}

struct ConditionalNavigationChildView: View {
    
    var body: some View {
        
        Text("This is the Child View.")
            .font(.headline)
    }
}


While this does fix the navigation issue in this case, other cases with multiple navigation links seem to be completely impossible. For example, say you replace the title with another navigation link. The second one will still work fine, as it is not conditional, but the first one, and all of its subviews, will get pushed back to the parent view on rotation.


In UIKit, this would never be a problem, as conditional navigation doesn't push back to the parent view like that. So is this a SwiftUI bug? Or is it intended behavior? If it is intended behavior, what solution is there for a view with multiple conditional navigation links?

Replies

Something I thought of was perhaps .offsetting the NavigationLinks that I want to be conditional to match the UI I want, but this is also really hacky and comes with other problems. Is there really no solution for this?

I am facing the exact same problem. When the device is rotated, the child view is poped and the parent view appears!! Any other workarounds?