swiftuiswiftui-navigationlinkios16.4

NavigationLink interfering with LazyVGrid Spacing


I have a table with three columns consisting of SF symbols, text, and money that I am aligning with LazyVGrid. I would like to add a navigation link (composed of the text and money columns) to a more detailed view, but when I do the third (money) column is not correctly aligned. It is crunched up against the text column. [[Here is a picture][1]][1]

The table is correctly aligned when the navigationLink is removed or if only the text column is the link. I have tried removing ScrollView, GeometryReader, and adding .frame(maxWidth: .infinity) to the view, but I didn't see any change in alignment of the third column.

The code below is a complete working demo of the problem. Thanks for looking!

// category model
struct Category:  Codable, Identifiable {

    var id = UUID()
    var catName: String
    var catBudget: Double
    var catPix: String
}
class CategoryModel: ObservableObject {

    @Published var catItem = [
        Category(catName: "Food", catBudget: 300.00, catPix: "cart"),
        Category(catName: "Lodging", catBudget: 1000.75, catPix: "bed.double.fill"),
        Category(catName: "Airplane", catBudget: 1700.25, catPix: "airplane"),
        Category(catName: "Train", catBudget: 250.40, catPix: "tram"),
        Category(catName: "Bus", catBudget: 10.26, catPix: "bus.fill")
    ]
}
struct ContentView: View {

    @ObservedObject var vm = CategoryModel()

    var columns: [GridItem] = [
        GridItem(.fixed(50)),
        GridItem(.fixed(200)),
        GridItem(.flexible())
    ]

    var body: some View {

        NavigationStack {
            GeometryReader { g in

                VStack (alignment: .leading) {
                    Rectangle()
                        .frame(height: g.size.height * 0.15)
                        .foregroundStyle(.white)

                    ScrollView {
                        ForEach(vm.catItem) { item in

                            Text("")
                                .frame(maxWidth: .infinity)

                            VStack {
                                LazyVGrid(
                                    columns: columns,
                                    alignment: .leading,
                                    spacing: 20
                                ) {

                                    // 1st table column
                                    Image(systemName: item.catPix)
                                        .imageScale(.large)

                                    NavigationLink {
                                        ShowDetail(item: item)
                                    } label: {

                                        // 2nd table column
                                        Text(item.catName)

                                        // 3rd table column
                                        let budget = item.catBudget.isNaN ? 0.0 : item.catBudget
                                        let gotBudget = budget.formatted(.currency(code: "USD").precision(.fractionLength(2)))
                                        Text(gotBudget)
                                    }
                                }
                            }
                            .padding(.leading, 15)
                            .foregroundStyle(.black)
                        }
                    }
                }
            }
        }
    }
}
struct ShowDetail: View {

    var item: Category

    var body: some View {
        
        VStack (alignment: .leading) {

            Text("Set \(item.catName) Budget")
                .font(Font.title3.bold())

        }
    }
}


  [1]: https://i.sstatic.net/FFfRF.jpg

Solution

  • You don't have 3 columns right now -- you have 2: the Image and the NavigationLink.

    For three columns, you could wrap the items in separate NavigationLinks:

    // 1st column
    Image(systemName: item.catPix)
        .imageScale(.large)
    
    // 2nd column
    NavigationLink {
        ShowDetail(item: item)
    } label: {
        Text(item.catName)
    }
    
    // 3rd table column
    NavigationLink {
        ShowDetail(item: item)
    } label: {
        let budget = item.catBudget.isNaN ? 0.0 : item.catBudget
        let gotBudget = budget.formatted(.currency(code: "USD").precision(.fractionLength(2)))
        Text(gotBudget)
    }