如何让SwiftUI Grid指定行可滚动并固定表头与总计行
SwiftUI 实现固定表头与总计行、中间内容滚动的Grid布局
要实现表头和总计行固定、中间内容可滚动的效果,不能直接给单个GridRow套ScrollView——因为Grid是整体布局容器,需要把结构拆分为表头Grid、滚动内容Grid、总计Grid三部分,用VStack组合,同时保证三部分的列宽对齐。
基础实现代码
import SwiftUI struct ContentView: View { // 模拟23行数据 let data: [(name: String, age: String)] = Array(repeating: ("Test User", "30"), count: 23) var body: some View { VStack(spacing: 0) { // 固定表头 Grid { GridRow { Text("Name") Text("Age") } .font(.headline) } .padding(.horizontal) // 中间可滚动内容区 ScrollView { Grid { ForEach(data, id: \.name) { item in GridRow { Text(item.name) Text(item.age) } } } .padding(.horizontal) } // 固定总计行 Grid { GridRow { Text("Total Age:") Text("\(data.reduce(0) { $0 + Int($1.age)! })") } } .font(.headline) .padding(.horizontal) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
优化列对齐(避免错位)
直接拆分Grid可能出现表头、内容、总计的列宽不一致的问题,用GeometryReader计算列宽,强制三部分列宽统一:
import SwiftUI struct ContentView: View { let data: [(name: String, age: String)] = Array(repeating: ("Test User", "30"), count: 23) // 自定义列宽比例 private let nameColumnRatio: CGFloat = 2/3 private let ageColumnRatio: CGFloat = 1/3 var body: some View { GeometryReader { geometry in let totalAvailableWidth = geometry.size.width - 32 // 减去左右padding总和 let nameColumnWidth = totalAvailableWidth * nameColumnRatio let ageColumnWidth = totalAvailableWidth * ageColumnRatio VStack(spacing: 0) { // 表头行 Grid { GridRow { Text("Name") .frame(width: nameColumnWidth, alignment: .leading) Text("Age") .frame(width: ageColumnWidth, alignment: .trailing) } .font(.headline) } .padding(.horizontal, 16) // 滚动内容区 ScrollView { Grid { ForEach(data, id: \.name) { item in GridRow { Text(item.name) .frame(width: nameColumnWidth, alignment: .leading) Text(item.age) .frame(width: ageColumnWidth, alignment: .trailing) } } } .padding(.horizontal, 16) } // 总计行 Grid { GridRow { Text("Total Age:") .frame(width: nameColumnWidth, alignment: .leading) Text("\(data.reduce(0) { $0 + Int($1.age)! })") .frame(width: ageColumnWidth, alignment: .trailing) } } .font(.headline) .padding(.horizontal, 16) } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
这样处理后,表头和总计行固定在界面顶部和底部,中间的23行数据可以自由滚动,同时所有列的宽度保持一致,不会出现错位问题。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

