SwiftUI中LazyVGrid实现自适应均匀间距布局的技术问询
SwiftUI 实现自适应间距的4列网格布局
核心思路
系统默认的网格组件(比如LazyVGrid)没法同时满足「部分行居中不填满、部分行填满整行」的混合需求,所以我们可以把数据按最多4个元素一组拆分,再针对每组的元素数量,用HStack结合Spacer实现对应布局:
- 1个元素:左右加
Spacer让元素居中 - 2/3个元素:左右和元素之间都加
Spacer,保证元素均匀分布且整体居中,不拉伸元素宽度 - 4个元素:仅在元素之间加
Spacer,让元素填满整行
完整代码实现
首先给数组加个分组扩展,方便按4个元素拆分:
extension Array { func chunked(into size: Int) -> [[Element]] { return stride(from: 0, to: count, by: size).map { Array(self[$0..<Swift.min($0 + size, count)]) } } }
然后实现自定义的自适应网格视图:
struct AdaptiveGridView<Content: View, Item: Identifiable>: View { let items: [Item] let content: (Item) -> Content let spacing: CGFloat init(items: [Item], spacing: CGFloat = 16, @ViewBuilder content: @escaping (Item) -> Content) { self.items = items self.spacing = spacing self.content = content } var body: some View { LazyVStack(spacing: spacing) { ForEach(items.chunked(into: 4), id: \.self) { rowItems in switch rowItems.count { case 1: HStack { Spacer() content(rowItems[0]) Spacer() } case 2, 3: HStack(spacing: spacing) { Spacer() ForEach(rowItems) { item in content(item) if item != rowItems.last { Spacer() } } Spacer() } case 4: HStack(spacing: spacing) { ForEach(rowItems) { item in content(item) if item != rowItems.last { Spacer() } } } default: EmptyView() } } } // 可选:给整个网格加外层内边距 .padding() } }
使用示例
// 定义数据模型 struct GridItemModel: Identifiable { let id: Int let text: String } struct ContentView: View { // 测试数据 let testItems = [ GridItemModel(id: 1, text: "Cell 1"), GridItemModel(id: 2, text: "Cell 2"), GridItemModel(id: 3, text: "Cell 3"), GridItemModel(id: 4, text: "Cell 4"), GridItemModel(id: 5, text: "Cell 5"), GridItemModel(id: 6, text: "Cell 6"), GridItemModel(id: 7, text: "Cell 7") ] var body: some View { AdaptiveGridView(items: testItems) { item in // 自定义每个单元格的样式 Text(item.text) .padding(.vertical, 12) .padding(.horizontal, 24) .background(Color.gray.opacity(0.2)) .cornerRadius(8) } } }
效果说明
- 1个元素:单元格居中显示,宽度为自身内容宽度
- 2/3个元素:单元格均匀分布且整体居中,元素之间的间距与到屏幕边缘的间距一致,不拉伸单元格宽度
- 4个元素:单元格填满整行,元素之间间距均匀
- 第5个及以后的元素自动换行,行与行之间的间距和单元格间距保持一致
内容的提问来源于stack exchange,提问作者Steve Meyers
相关产品推荐
相关产品推荐

