如何构建自适应屏幕宽度、项宽动态的等高行照片网格?
实现列数可配置、每行等高的照片网格方案
要实现列数可修改、每行高度一致、照片宽度自适应填满屏幕的网格效果,核心是统一行内图片的高度比例,再整体缩放适配屏幕宽度。以下是具体实现方案:
1. 修正图片单元格视图
将图片的缩放模式从scaledToFit改为scaledToFill,并通过传入的缩放因子约束尺寸,避免图片变形:
struct MediaCellView: View { let metadata: tableMetadata let scaleFactor: CGFloat @StateObject private var viewModel = MediaCellViewModel() var body: some View { Image(uiImage: viewModel.thumbnail) .resizable() .scaledToFill() .frame( width: CGFloat(metadata.width == 0 ? 500 : metadata.width) * scaleFactor, height: CGFloat(metadata.height == 0 ? 500 : metadata.height) * scaleFactor ) .clipped() .onAppear { viewModel.configure(metadata: metadata) viewModel.downloadThumbnail() } } }
2. 构建主网格视图
将图片数据按指定列数分块为行,计算每行的统一缩放比例,再用HStack+LazyVStack组合实现每行等高的网格:
struct PhotoGridView: View { let viewModel: YourViewModel let columnsCount: Int // 可配置的列数 // 将数据按列数分块为行数据 private var rowData: [[tableMetadata]] { viewModel.metadatas.chunked(into: columnsCount) } var body: some View { LazyVStack(spacing: 0) { ForEach(rowData, id: \.self) { rowMetadatas in let scale = calculateScale(for: rowMetadatas) HStack(spacing: 0) { ForEach(rowMetadatas, id: \.self) { metadata in MediaCellView(metadata: metadata, scaleFactor: scale) } } } } } // 计算每行图片的统一缩放比例 private func calculateScale(for rowMetadatas: [tableMetadata]) -> CGFloat { let screenWidth = UIScreen.main.bounds.width // 取行内图片的最大高度作为基准高度,保证行内所有图片最终高度一致 let maxRowHeight = rowMetadatas.reduce(CGFloat(500)) { currentMax, metadata in max(currentMax, CGFloat(metadata.height == 0 ? 500 : metadata.height)) } // 计算所有图片缩放至基准高度后的总宽度 var totalScaledWidth: CGFloat = 0 for metadata in rowMetadatas { let imgWidth = CGFloat(metadata.width == 0 ? 500 : metadata.width) let imgHeight = CGFloat(metadata.height == 0 ? 500 : metadata.height) let scaleToBase = maxRowHeight / imgHeight totalScaledWidth += imgWidth * scaleToBase } // 返回适配屏幕宽度的最终缩放比例 return screenWidth / totalScaledWidth } }
3. 关键逻辑说明
- 统一行高:以行内最高图片的高度为基准,将其他图片按比例缩放至该高度,保证每行所有图片高度一致
- 适配屏幕宽度:计算缩放至基准高度后的行总宽度,再用屏幕宽度除以该总宽度,得到最终缩放比例,确保整行刚好填满屏幕
- 图片无变形:使用
scaledToFill+clipped保证图片按比例填满容器,同时裁剪超出部分,避免拉伸变形
你之前方案的问题点
scaledToFit的问题:该模式会保持图片比例但不会填满容器,导致行高无法统一,图片之间出现空隙- LazyVGrid的局限性:默认的灵活网格列配置是基于屏幕宽度均分,无法根据每行图片的原始比例动态调整宽度
- 缩放逻辑错误:之前的
getSize方法先将图片缩放至行内最大高度,再计算适配比例,但未正确关联最终的视图尺寸约束
内容的提问来源于stack exchange,提问作者Milen Pivchev
相关产品推荐
相关产品推荐

