You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI按钮网格布局问题:基于最大尺寸统一按钮尺寸

解决SwiftUI按钮网格均分空间且统一高度的问题

要实现按钮均分水平空间且所有按钮高度统一的网格布局,可以通过PreferenceKey收集最大高度的方式解决,以下是具体实现:

步骤1:定义高度收集的PreferenceKey

首先创建一个PreferenceKey,用于收集所有按钮的渲染高度并取最大值:

struct ButtonHeightPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = 0
    
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value = max(value, nextValue())
    }
}

步骤2:修改ContentView实现统一布局

更新你的ContentView,通过PreferenceKey获取所有按钮的最大高度,再将这个高度应用到所有按钮上:

struct ContentView: View {
    let texts = [["Short", "A bit longer text", "bbb"],
                 ["a", "A bit longer text", "This is a very long text that might not fit in one line"],
                 ["a", "b", "c"]
                 ]
    
    @State private var maxButtonHeight: CGFloat = 0
    
    var body: some View {
        VStack(spacing: 8) {
            ForEach(texts, id: \.self) { row in
                HStack(spacing: 8) {
                    ForEach(row, id: \.self) { text in
                        Button{ } label: {
                            Text(text)
                                .foregroundStyle(.white)
                                .padding()
                                .background(.red)
                                .clipShape(Capsule())
                                // 测量按钮实际渲染高度并传递给PreferenceKey
                                .background(
                                    GeometryReader { geo in
                                        Color.clear
                                            .preference(key: ButtonHeightPreferenceKey.self, value: geo.size.height)
                                    }
                                )
                                // 均分水平空间 + 使用统一的最大高度
                                .frame(maxWidth: .infinity, height: maxButtonHeight)
                        }
                    }
                }
                .frame(maxWidth: .infinity)
            }
        }
        .padding()
        // 更新最大高度状态
        .onPreferenceChange(ButtonHeightPreferenceKey.self) { newHeight in
            maxButtonHeight = newHeight
        }
    }
}

#Preview {
    ContentView()
}

原理说明

  1. 高度收集:通过GeometryReader测量每个按钮的实际渲染高度,借助ButtonHeightPreferenceKey收集所有高度并保留最大值。
  2. 统一高度:将收集到的最大高度赋值给所有按钮的height参数,确保所有按钮高度一致。
  3. 均分空间:按钮的frame(maxWidth: .infinity)会让每个按钮自动填充所在HStack的可用水平空间,实现均分效果。
  4. 间距优化:给VStack和HStack添加spacing参数,让布局更美观(可根据需求调整数值)。

为什么原代码无法满足需求

原代码中每行的HStack使用fixedSize(horizontal: false, vertical: true),仅能保证该行内按钮高度一致,但不同行之间没有共享高度信息,导致各行高度独立,无法实现全局统一高度。

内容的提问来源于stack exchange,提问作者Artium

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 15:36:09