Search code examples
swiftuiuinavigationbarswiftui-navigationlinklazyvgrid

How can the navigation bar title be set as the item's name upon tapping on a specific item?


I'm creating a dinner menu with various food item's that can be tapped. Each item is wrapped in a NavigationLink that leads to it's detail page.

How can the item's name be placed as the navigation bar title for each item? Here's the entire MenuItemsView struct and a gif to demonstrate where I'd like the food item title just as in the previous Menu screen.

struct MenuItemsView: View {
    let food = (1...12).map { "Food \($0)" }
    let drinks = (1...8).map { "Drink \($0)" }
    let dessert = (1...4).map { "Dessert \($0)" }
    
    let columns = [
        GridItem(.adaptive(minimum: 80))
        ]
    
    var body: some View {
        NavigationView {
                ScrollView {
                    VStack {
                        Text("Food")
                            .frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
                            .font(.title)
                            .padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
                        LazyVGrid(columns: columns, spacing: 5.0) {
                            ForEach(food, id: \.self) { item in
                                NavigationLink(destination: MenuItemDetailsView()) {
                                    VStack {
                                        ColorSquare(color: .black)
                                        Text(item)
                                        
                                    }
                                    .padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
                                }
                            }
                            
                        }
                    }
                    VStack {
                        Text("Drinks")
                            .frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
                            .font(.title)
                            .padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
                        LazyVGrid(columns: columns, spacing: 5.0) {
                            ForEach(drinks, id: \.self) { item in
                                VStack {
                                    ColorSquare(color: .black)
                                    Text(item)
                                }
                                .padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
                            }
                            
                        }
                    }
                    VStack {
                        Text("Desert")
                            .frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
                            .font(.title)
                            .padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
                        LazyVGrid(columns: columns, spacing: 5.0) {
                            ForEach(dessert, id: \.self) { item in
                                VStack {
                                    ColorSquare(color: .black)
                                    Text(item)
                                }
                                .padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
                            }
                            
                        }
                    }
                    
                }
                .navigationBarTitle("Menu")
                .navigationBarItems(trailing:
                    Button(action: {
                        print("Edit button pressed...")
                    }) {
                        NavigationLink(destination: MenuItemsOptionView()) {
                            Image(systemName: "slider.horizontal.3")
                        }
                    }
                )
            }
        }
}

Food Details Demonstration

As a bonus, if anyone can tell me how to properly line up the Color Squares with their respective category name and Menu title, I'd appreciate it a lot lol. Thanks!


Solution

  • I was able to figure out this issue. Here's how:

    I passed in itemName: item as a NavigationLink parameter as the destination. In the MenuItemDetailsView file, the body was set up with a Text view and navigationBarTitle modifier with itemName passed in. itemName was created above the MenuItemDetailsView struct before being passed of course. Here is the MenuItemDetailsView and MenuItemsView code that solved the problem as well as a quick demonstration:

    MenuItemDetailsView

    import SwiftUI
    
    struct MenuItemDetailsView: View {
        var itemName: String
        
        var body: some View {
            Text(itemName)
                .navigationBarTitle(itemName)
        }
    }
    
    struct MenuItemDetailsView_Previews: PreviewProvider {
        static var previews: some View {
            let food = (1...12).map { "Food \($0)" }
            
            return Group {
                ForEach(food, id: \.self) { item in
                    NavigationView {
                        MenuItemDetailsView(itemName: item)
                    }
                    .previewDisplayName(item)
                }
            }
        }
    }
    

    MenuItemsView

    import SwiftUI
    
    struct ColorSquare: View {
        let color: Color
        
        var body: some View {
            color
                .frame(width: 100, height: 100)
        }
    }
    
    struct MenuItemsView: View {
        let food = (1...12).map { "Food \($0)" }
        let drinks = (1...8).map { "Drink \($0)" }
        let dessert = (1...4).map { "Dessert \($0)" }
        
        let columns = [
            GridItem(.adaptive(minimum: 80))
            ]
        
        var body: some View {
            NavigationView {
                    ScrollView {
                        VStack {
                            Text("Food")
                                .frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
                                .font(.title)
                                .padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
                            LazyVGrid(columns: columns, spacing: 5.0) {
                                ForEach(food, id: \.self) { item in
                                    NavigationLink(destination: MenuItemDetailsView(itemName: item)) {
                                        VStack {
                                            ColorSquare(color: .black)
                                            Text(item)
                                            
                                        }
                                        .padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
                                    }
                                }
                                
                            }
                        }...more code
    

    Food Item Nav Title Solved Demo