SwiftUI中使用Stack实现网格布局的优化问题
SwiftUI Stack网格布局优化方案
优化后的完整代码
import SwiftUI // 用于传递视图高度的PreferenceKey struct ViewHeightKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } } struct ForStackOverflow: View { let spacerSize: CGFloat = 1 @State private var leftContainerHeight: CGFloat = 0 var body: some View { GeometryReader { geometry in let totalWidth = geometry.size.width // 计算与A/D一致的单组件宽度 let componentWidth = (totalWidth - 3 * spacerSize) / 4 VStack(spacing: spacerSize) { HStack(spacing: spacerSize) { makeComponent(text: "A") makeComponent(text: "B") makeComponent(text: "C") makeComponent(text: "D") } HStack(spacing: spacerSize) { VStack(spacing: spacerSize) { HStack(spacing: spacerSize) { makeComponent(text: "E") makeComponent(text: "F") makeComponent(text: "G") } HStack(spacing: spacerSize) { makeComponent(text: "H") makeComponent(text: "I") makeComponent(text: "J") } HStack(spacing: spacerSize) { makeComponent(text: "K") } } // 捕获左侧容器的实际高度 .background( GeometryReader { proxy in Color.clear .preference(key: ViewHeightKey.self, value: proxy.size.height) } ) makeComponent(text: "L") .frame(width: componentWidth) .frame(height: leftContainerHeight) } } } .onPreferenceChange(ViewHeightKey.self) { newHeight in leftContainerHeight = newHeight } } func makeComponent(text: String) -> some View { Text(text) .frame(minWidth: 0, maxWidth: .infinity) .frame(height: 80) .background(Color.red) .foregroundColor(.white) } } struct ForStackOverflow_Previews: PreviewProvider { static var previews: some View { ForStackOverflow() } }
问题1:L宽度与D一致的优化
- 替换硬编码的
UIScreen.main.bounds.width,改用GeometryReader获取当前视图的实际可用宽度,适配分屏、安全区等复杂场景。 - 通过公式
(总宽度 - 3*间距)/4计算出和A/D完全一致的单组件宽度,直接应用到L的宽度设置中,保证布局匹配。
问题2:L高度匹配G+J+K总和的优化
- 采用
PreferenceKey机制自动捕获左侧容器(包含G、J、K的VStack)的实际高度,无需手动计算80*3 + 2*间距这类固定值。 - 实现逻辑:
- 定义
ViewHeightKey继承PreferenceKey,用于传递高度数据。 - 在左侧VStack的背景中嵌入
GeometryReader,获取容器高度并通过preference传递。 - 用
onPreferenceChange接收高度值,同步设置L的高度,实现自动匹配。
- 定义
内容的提问来源于stack exchange,提问作者Ryo
相关产品推荐
相关产品推荐

