如何调整VStack尺寸以匹配LazyVGrid元素大小?
SwiftUI:让左侧VStack元素匹配LazyVGrid单元格尺寸
我拥有一个包含3个弹性列、元素宽高比为1的LazyVGrid,其外围容器在垂直方向固定。我希望调整左侧VStack内的元素,使其保持1的宽高比,从而让高度与网格元素尺寸匹配,最终效果为硬编码.frame()实现的示例图。当前使用.aspectRatio(1, contentMode: .fill)存在问题,相关代码如下:
VStack(spacing: 0) { HStack(spacing: 0) { ForEach(answerRows, id: \.self) { row in RoundedRectangle(cornerRadius: 50).foregroundColor(.gray) } } .frame(maxWidth: .infinity, maxHeight: 40, alignment: .center) .border(.orange, width: 2) .padding(.leading, 40) HStack(spacing: 0) { VStack(spacing: 0) { // 需要基于网格尺寸调整大小 ForEach(answerRows, id: \.self) { row in RoundedRectangle(cornerRadius: 30).foregroundColor(.gray) } .aspectRatio(1, contentMode: .fill) // 这里存在问题 } .frame(maxWidth: .infinity, maxHeight: .infinity) .border(.purple, width: 1) LazyVGrid(columns: threeColumnGrid, spacing: 0) { ForEach(answerRows.flatMap{$0}, id: \.self) { row in ZStack { Rectangle() .aspectRatio(1, contentMode: .fill) .border(Color(red: 29/255, green: 29/255, blue: 40/255), width: 3) .foregroundColor(Color(red: 50/255, green: 50/255, blue: 69/255)) } } } .frame(maxWidth: .infinity, maxHeight: .infinity) .clipShape(RoundedRectangle(cornerRadius: 20)) } .frame(maxWidth: .infinity, maxHeight: .infinity) .fixedSize(horizontal: false, vertical: true) .border(.green, width: 1) } .border(.blue, width: 1)
当前效果

期望效果

解决方案
问题出在给ForEach直接添加.aspectRatio的方式无法关联网格单元格的尺寸,需要通过GeometryReader获取网格的宽度,进而计算出单元格尺寸,再应用到左侧元素上:
- 确保网格列定义为弹性列(如果还没定义):
private let threeColumnGrid = [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]
- 修改左侧VStack所在的HStack部分代码:
HStack(spacing: 0) { // 用GeometryReader捕获右侧网格的尺寸 GeometryReader { gridProxy in let columnCount = threeColumnGrid.count let cellSize = gridProxy.size.width / CGFloat(columnCount) // 计算单个单元格的宽高 VStack(spacing: 0) { ForEach(answerRows, id: \.self) { row in RoundedRectangle(cornerRadius: 30).foregroundColor(.gray) .frame(width: cellSize, height: cellSize) // 强制宽高比1:1 } } .frame(maxHeight: .infinity, alignment: .center) // 垂直方向居中对齐 } .border(.purple, width: 1) .frame(maxWidth: .infinity, maxHeight: .infinity) LazyVGrid(columns: threeColumnGrid, spacing: 0) { ForEach(answerRows.flatMap{$0}, id: \.self) { row in ZStack { Rectangle() .aspectRatio(1, contentMode: .fill) .border(Color(red: 29/255, green: 29/255, blue: 40/255), width: 3) .foregroundColor(Color(red: 50/255, green: 50/255, blue: 69/255)) } } } .frame(maxWidth: .infinity, maxHeight: .infinity) .clipShape(RoundedRectangle(cornerRadius: 20)) } .frame(maxWidth: .infinity, maxHeight: .infinity) .fixedSize(horizontal: false, vertical: true) .border(.green, width: 1)
原理说明
- 通过
GeometryReader获取右侧网格的总宽度,除以列数得到单个单元格的尺寸; - 给左侧每个圆角矩形设置相同的宽高,确保宽高比始终为1,且尺寸与网格单元格完全匹配;
- 用
frame(maxHeight: .infinity, alignment: .center)让左侧VStack在垂直方向居中对齐,和网格布局保持一致。
内容的提问来源于stack exchange,提问作者Nader
相关产品推荐
相关产品推荐

