SwiftUI:如何实现随子视图宽度变化的自适应列数动态网格?
SwiftUI 自适应列数网格(适配动态文本缩放)
核心实现思路
通过监听系统动态文本尺寸,结合屏幕可用宽度计算适配的列数,使用LazyVGrid构建网格,确保单元格填满宽度且文本不截断,同时保证每行单元格数量统一。
单元格视图实现
先定义包含图片和文本的单元格,确保文本能自适应高度、不截断:
struct GridItemView: View { let imageName: String let text: String var body: some View { VStack(spacing: 8) { Image(systemName: imageName) .resizable() .aspectRatio(contentMode: .fit) .frame(height: 40) Text(text) .multilineTextAlignment(.center) .fixedSize(horizontal: false, vertical: true) // 允许文本换行,高度自适应 } .padding() .frame(maxWidth: .infinity) // 填满对应列宽 .background(Color.gray.opacity(0.1)) .cornerRadius(8) } }
自适应网格主视图
通过dynamicTypeSize监听文本缩放,结合屏幕宽度计算列数,构建统一列数的网格:
struct AdaptiveGridView: View { // 模拟3列5行的数据源 let items: [(image: String, text: String)] = [ ("1.circle", "项目1"), ("2.circle", "项目2"), ("3.circle", "项目3"), ("4.circle", "项目4"), ("5.circle", "项目5"), ("6.circle", "项目6"), ("7.circle", "项目7"), ("8.circle", "项目8"), ("9.circle", "项目9"), ("10.circle", "项目10"), ("11.circle", "项目11"), ("12.circle", "项目12"), ("13.circle", "项目13"), ("14.circle", "项目14"), ("15.circle", "项目15") ] // 监听系统动态文本尺寸 @Environment(\.dynamicTypeSize) private var dynamicTypeSize var body: some View { GeometryReader { geometry in ScrollView { LazyVGrid(columns: gridColumns(for: geometry.size.width), spacing: 16) { ForEach(items, id: \.text) { item in GridItemView(imageName: item.image, text: item.text) } } .padding() } } } // 根据文本尺寸和屏幕宽度计算列数 private func gridColumns(for width: CGFloat) -> [GridItem] { let minColumnWidth: CGFloat // 按动态文本尺寸区间设置最小列宽阈值 switch dynamicTypeSize { case .xSmall, .small, .medium: minColumnWidth = 100 // 默认小文本,3列布局 case .large, .xLarge: minColumnWidth = 150 // 文本增大,自动切换2列 case .xxLarge, .xxxLarge, .accessibility1...: minColumnWidth = 200 // 大文本/无障碍模式,切换单列 default: minColumnWidth = 100 } // 计算列数,确保至少1列 let columnCount = max(1, Int(width / minColumnWidth)) return Array(repeating: GridItem(.flexible(), spacing: 16), count: columnCount) } }
关键说明
- 利用
@Environment(\.dynamicTypeSize)精准捕获文本缩放级别,不同级别对应不同的最小列宽,触发列数切换 GeometryReader获取屏幕可用宽度,结合最小列宽计算出当前能容纳的整数列数,保证每行单元格数量一致- 单元格通过
fixedSize(horizontal: false, vertical: true)让文本自动换行,避免截断;frame(maxWidth: .infinity)确保单元格填满列宽,解决自定义Layout出现的填充不充分问题
内容的提问来源于stack exchange,提问作者Oguzhan Varsak
相关产品推荐
相关产品推荐

