Align Subtitles and Footers with LazyVGrid?

632 Views Asked by At

I have a question about using LazyVGrid to align the subtitles and footers for each column. Say I have a view like this:

 Title


 Subtitle A     Subtitle B     Subtitle C

   row1A          row1B          row1C
   row2A          row2B          row2C
   row3A          row3B          row3C
   row4A          row4B          row4C
   row5A          row5B          row5C

  Total A        Total B        Total C

Currently I use Geometry Reader to display the headers and footers and LazyVGrid to display the data. I have noticed that if I line up the subtitles with a 12 ProMax simulator then view my setup on the 12 Mini simulator that the Mini titles have moved and don't appear very professional. Is it possible to use something like the following with LazyVGrid to not only display the data but also the subtitles and footers? Using pinnedViews: [] I can display the first column header, but how do I display all three subtitles and footers? There is some Apple documentation here on using section headers but nothing on multiple section headers and footers.

private var columns: [GridItem] = [
        GridItem(.flexible()),
        GridItem(.flexible()),
        GridItem(.flexible())
    ]
    var body: some View {

    GeometryReader { g in
        ScrollView {
            VStack (alignment: .leading) {

   ShowTitle()

   ShowSubTitle()

       LazyVGrid(
           columns: columns,
           alignment: .leading,
           spacing: 10,  // vertical spacing
           pinnedViews: [.sectionHeaders, .sectionFooters]
       ) {

           Section(header: Text("Subtitle A")
                 .font(.headline)) {
               ForEach(0..<self.categories.catItem.count, id: \.self) { index in
                  ShowRow(index: index)
                }
             }
          }
1

There are 1 best solutions below

4
On BEST ANSWER

I mocked this up off of the Apple example at Grouping Data with Lazy Stack Views. The trick is to put the LazyVStack inside of the ForEach that goes through each section like this:

struct LazyVGridSectioned: View {
    let sections = [
        ColorData(color: .red, name: "Reds", footerInfo: "Red Footer Info"),
        ColorData(color: .green, name: "Greens", footerInfo: "Green Footer Info"),
        ColorData(color: .blue, name: "Blues", footerInfo: "Blue Footer Info")
    ]
    
    var body: some View {
        ScrollView {
            HStack {
                ForEach(sections) { section in
                    LazyVStack(spacing: 1, pinnedViews: [.sectionHeaders, .sectionFooters]) {
                        Section(header: SectionHeaderView(colorData: section), footer: SectionFooterView(colorData: section)) {
                            ForEach(section.variations) { variation in
                                section.color
                                    .brightness(variation.brightness)
                                    .frame(height: 20)
                            }
                        }
                    }
                }
            }
        }
    }
}
    

struct SectionHeaderView: View {
    var colorData: ColorData

    var body: some View {
        HStack {
            Spacer()
            Text("Header for \(colorData.name)")
                .font(.headline)
                .foregroundColor(colorData.color)
            Spacer()
        }
        .padding()
        .background(Color.primary
                        .colorInvert()
                        .opacity(0.75))
    }
}

struct SectionFooterView: View {
    var colorData: ColorData

    var body: some View {
        HStack {
            Spacer()
            Text(colorData.footerInfo)
                .font(.headline)
                .foregroundColor(colorData.color)
            Spacer()
        }
        .padding()
        .background(Color.primary
                        .colorInvert()
                        .opacity(0.75))
    }
}
    

struct ColorData: Identifiable {
    let id = UUID()
    let name: String
    let footerInfo: String // Add parameter in ColorData
    let color: Color
    let variations: [ShadeData]

    struct ShadeData: Identifiable {
        let id = UUID()
        var brightness: Double
    }

    // Add it to the init as well
    init(color: Color, name: String, footerInfo: String) {
        self.name = name
        self.color = color
        self.footerInfo = footerInfo // Assign it here
        self.variations = stride(from: 0.0, to: 0.5, by: 0.1)
            .map { ShadeData(brightness: $0) }
    }
}