swiftuivstacklazyvgridlazyhgrid

SwiftUI - grid / table with column headings


I'm trying to achieve a design which essentially has the following layout:

enter image description here

So I need column headings for this table or grid view. The second column does not need a heading.

This seems like a job for a LazyVGrid or LazyHGrid, however I can't seem to find a solution which neatly includes headings like this - it all seems a bit hacky.

Wondering if I am missing a better way to achieve this. I could of course try and create VStacks within HStacks, but this just seems like something which should be accomplished more intelligently than this.


Solution

  • You can just pass the headers into the LazyVGrid before you show the content:

    struct Item: Identifiable {
        let id = UUID()
        var item: String
        var description: String = "This is the item description"
        var quantity: Int = 1
        var price: Double = 0
    }
    
    
    struct ContentView: View {
        
        let data = [
            Item(item: "Image 1", quantity: 2, price: 1.99),
            Item(item: "Image 2", quantity: 1, price: 3.99),
            Item(item: "Image 3", quantity: 5, price: 9.99),
        ]
        
        let columns = [
            GridItem(.flexible(), alignment: .topLeading),
            GridItem(.flexible(minimum: 150), alignment: .topLeading),
            GridItem(.flexible(), alignment: .topLeading),
            GridItem(.flexible(), alignment: .topLeading),
        ]
        
        var body: some View {
            
            LazyVGrid(columns: columns) {
                
                // headers
                Group {
                    Text("Item")
                    Text("")
                    Text("Qty")
                    Text("Price")
                }
                .font(.headline)
                
                // content
                ForEach(data) { item in
                    Text(item.item)
                    Text(item.description)
                    Text("\(item.quantity)")
                    Text("$\(item.price, specifier: "%.2f")")
                }
            }
            .padding()
        }
    }