SwiftUI中如何实现带横竖连续分隔线的分页网格视图
SwiftUI实现带连续横竖分隔线的分页网格视图解决方案
问题说明
需要实现带有连续横向和纵向分隔线的分页网格视图,要求两行网格项高度一致,当前代码通过缩小第二行高度的取巧方式无法满足需求,需采用更可靠的实现方案。
最佳实现方案
核心思路是将分隔线与网格项解耦,通过自定义背景视图统一绘制完整的分隔线,而非在每个网格项内部添加分隔线。这样既能保证两行高度一致,又能让分隔线连续无断裂。
完整代码
struct ContentView: View { // 统一设置两行网格高度为90 let rows = [GridItem(.fixed(90)), GridItem(.fixed(90))] // 每页显示4列网格项 let columnsPerPage = 4 // 单个网格项的尺寸 let itemSize = CGSize(width: 80, height: 80) var body: some View { TabView { pageView(startIndex: 0) pageView(startIndex: 8) } .tabViewStyle(PageTabViewStyle(indexDisplayMode: .always)) } func pageView(startIndex: Int) -> some View { ScrollView(.horizontal, showsIndicators: false) { LazyHGrid(rows: rows, spacing: 0) { ForEach(startIndex..<startIndex+8, id: \.self) { index in // 仅放置网格内容,分隔线统一由背景视图处理 RoundedRectangle(cornerRadius: 10) .fill(Color.blue) .frame(width: itemSize.width, height: itemSize.height) } } // 添加自定义分隔线背景 .background( GridDividers(rows: rows.count, columns: columnsPerPage, itemSize: itemSize, lineWidth: 2, lineColor: .gray) ) .padding(.horizontal) } } } // 自定义视图:绘制网格的横竖分隔线 struct GridDividers: View { let rows: Int let columns: Int let itemSize: CGSize let lineWidth: CGFloat let lineColor: Color var body: some View { GeometryReader { geo in ZStack(alignment: .topLeading) { // 绘制纵向分隔线:每两列之间一条 ForEach(1..<columns) { colIndex in Rectangle() .fill(lineColor) .frame(width: lineWidth) .offset( x: itemSize.width * CGFloat(colIndex) + lineWidth * CGFloat(colIndex - 1), y: 0 ) .frame(height: geo.size.height) } // 绘制横向分隔线:两行之间一条 ForEach(1..<rows) { rowIndex in Rectangle() .fill(lineColor) .frame(height: lineWidth) .offset( x: 0, y: itemSize.height * CGFloat(rowIndex) + lineWidth * CGFloat(rowIndex - 1) ) .frame(width: geo.size.width) } } } } }
方案解析
- 统一网格高度:将两行
GridItem的高度都设置为90,避免取巧式的高度调整。 - 分隔线解耦:通过
GridDividers自定义视图在网格背景绘制分隔线,确保分隔线是独立于网格项的完整线条。 - 精确位置计算:利用
GeometryReader获取网格的实际尺寸,结合网格项尺寸和分隔线宽度,精确计算每条分隔线的偏移位置,保证线条连续对齐。 - 扩展性强:如果需要调整网格项尺寸、分隔线宽度或颜色,只需修改对应参数即可,无需修改网格项的布局逻辑。
内容的提问来源于stack exchange,提问作者Noah Wilder
相关产品推荐
相关产品推荐

