文章

使用惰性 Stack 视图对数据进行分组

将内容拆分成惰性 stack 视图中的多个逻辑部分。

概览

LazyHStack (英文)LazyVStack (英文) 视图都可以显示整理为多个逻辑部分的视图组,从而分别将其子项排列成水平生长和垂直生长的直线。之所以称这些 stack 为“惰性”,是因为 stack 视图仅在需要在屏幕上渲染项目时才会创建项目。与 stack 视图一样,惰性 stack 不包括对滚动的任何固有支持,并且你应将惰性 stack 视图包装在 ScrollView (英文) 容器中。

若要对惰性 stack 视图中的内容或数据进行分组,请使用 Section (英文) 实例作为已分组视图集合的容器。Section (英文) 视图本身没有任何直观的表示形式,但是可以包含页眉和页脚视图,这些视图可随着 stack 的内容进行滚动,或者你可以将它们固定在 ScrollView (英文) 的顶部或底部。

本文中的代码示例构建了一个用户界面来直观地呈现三原色的不同色度。Stack 中的每个部分都代表一种原色,其中包含五个子视图,每个子视图都显示该颜色的一个不同变体。

截屏显示了一个包含多个部分的惰性 stack 视图。每个部分的页眉包含颜色的名称,后面是一组视图,其中显示了该颜色的不同色度。

准备数据

与 stack 中包含的视图一样,在通过 ForEach (英文) 迭代时,每个 Section (英文) 都必须经过唯一标识。在此示例中,ColorData 实例代表各个部分,ShadeData 实例代表一个部分中每种颜色的色度。ColorDataShadeData 均遵从 Identifiable (英文) 协议。


struct ColorData: Identifiable {
    let id = UUID()
    let name: String
    let color: Color
    let variations: [ShadeData]


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


    init(color: Color, name: String) {
        self.name = name
        self.color = color
        self.variations = stride(from: 0.0, to: 0.5, by: 0.1)
            .map { ShadeData(brightness: $0) }
    }
}

显示带页眉和页脚的部分

下面的 ColorSelectionView 为每个原色设置了一个包含 ColorData 实例的数组。LazyVStack (英文) 迭代颜色数据的数组以创建各个部分,然后迭代 variations 以根据色度创建视图。


struct ColorSelectionView: View {
    let sections = [
        ColorData(color: .red, name: "Reds"),
        ColorData(color: .green, name: "Greens"),
        ColorData(color: .blue, name: "Blues")
    ]


    var body: some View {
        ScrollView {
            LazyVStack(spacing: 1) {
                ForEach(sections) { section in
                    Section(header: SectionHeaderView(colorData: section)) {
                        ForEach(section.variations) { variation in
                            section.color
                                .brightness(variation.brightness)
                                .frame(height: 20)
                        }
                    }
                }
            }
        }
    }
}

使用 Section (英文) 视图对数据进行分组,并使用 headerfooter 属性传入页眉或页脚视图。此示例实施了一个 SectionHeaderView 作为页眉视图,其中包含一个半透明的 stack 视图以及 Text (英文) 标签中该部分颜色的名称。


struct SectionHeaderView: View {
    var colorData: ColorData


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

有关使用 ForEach (英文) 在 stack 中重复视图的更多信息,请参阅“创建高性能的可滚动 Stack”。

使重要信息保持可见

默认情况下,一个部分的页眉和页脚视图将与该部分的内容同步滚动。如果你想要让页眉和页脚视图始终保持可见 (无论相关部分的顶部或底部是否可见),可以为惰性 stack 视图的 pinnedViews 属性指定一组 PinnedScrollableViews (英文)


LazyVStack(spacing: 1, pinnedViews: [.sectionHeaders]) {
    // ...
}

LazyVStack (英文) 容器中,页眉附加到顶部,页脚附加到底部。在 LazyHStack (英文) 容器中,页眉附加到前缘,页脚附加到后缘。

通过此更改,在用户开始滚动时,相关部分的页眉会固定到视图顶部。

截屏显示了一个具有多个部分的惰性 stack 视图,其配置方式与第一个截屏中的相同。在这个截屏中,用户已向下滚动页面,彩色视图显示在相关部分的页眉后面,页眉已固定到容器视图的顶部。

另请参阅

惰性 Stack