AD Progress
AD Progress

Reputation: 5076

SwiftUI ViewModifier not working as a NavigationLink

I have the following ViewModifier and it does not work:

import SwiftUI

struct NavLink: ViewModifier {
    let title: String
    
    func body(content: Content) -> some View {
        NavigationLink(destination: content) {
            Text(title)
        }
    }
}

extension View {
    func navLink(title: String) -> some View {
        modifier(NavLink(title: title))
    }
}

If I use that as follows:

import SwiftUI

struct MainScreen: View {
    var body: some View {
        NavigationStack() {
            VStack {
                // This does not work
                NavStackScreen()
                    .navLink(title: "Nav Stack")

                // But this does
                Helper.linked(to: NavStackScreen(), title: "Nav Stack 2")
            }
        }
    }
}

struct Helper {
    static func linked(to destination: some View, title: String) -> some View {
        NavigationLink(destination: destination) {
            Text(title)
        }
    }
}

It creates the link and pushes a new view onto the screen if tapped; however, the contents of the NavStackScreen are not displayed, only an empty screen. Any ideas about what is going on?

Contents of NavStackScreen for reference:

struct NavStackScreen: View {
    var body: some View {
        Text("Nav Stack Screen")
            .font(.title)
            .navigationTitle("Navigation Stack")
    }
}

If I use a static helper function within a helper struct, then it works correctly:

    static func linked(to destination: some View, title: String) -> some View {
        NavigationLink(destination: destination) {
            Text(title)
        }
    }

I added the full code of the MainView for reference and updated the example with more detail for easy reproduction.

Upvotes: 2

Views: 662

Answers (1)

Cristik
Cristik

Reputation: 32785

The modifier doesn't work because the content argument is not the actual view being modified, but instead is a proxy:

content is a proxy for the view that will have the modifier represented by Self applied to it.

Reference.

This is what a quick debugging over the modifier shows:

(lldb) po content
SwiftUI._ViewModifier_Content<SwiftUIApp.NavLink>()

As the proxy is an internal type of SwiftUI, we can't know for sure why NavigationLink doesn't work with it.

A workaround would be to skip the modifier, and only add the extension over View:

extension View {
    func navLink(title: String) -> some View {
        NavigationLink(destination: content) {
            Text(title)
        }
    }
}

Upvotes: 1

Related Questions