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

SwiftUI中如何测量VStack内视图高度及适配安全区?

VStack可变高度获取与安全区适配方案

一、获取中间游戏棋盘的尺寸

在SwiftUI里,动态获取视图尺寸最可靠的方式是用GeometryReader。把它作为目标视图的背景,就能精准捕获视图的实际大小,代码示例如下:

struct GameView: View {
    @State private var boardSize: CGSize = .zero // 存储棋盘尺寸
    
    var body: some View {
        VStack(spacing: 0) {
            // 顶部固定高度矩形
            Rectangle()
                .frame(height: 140)
                .foregroundColor(.red)
            
            // 中间游戏棋盘:通过背景GeometryReader获取尺寸
            Rectangle()
                .foregroundColor(.green)
                .background(
                    GeometryReader { proxy in
                        Color.clear
                            .onAppear {
                                boardSize = proxy.size
                                print("棋盘宽高:\(boardSize.width) x \(boardSize.height)")
                            }
                            .onChange(of: proxy.size) { newSize in
                                boardSize = newSize // 适配布局变化(竖屏固定可省略,保留更健壮)
                            }
                    }
                )
            
            // 底部固定高度矩形
            Rectangle()
                .frame(height: 140)
                .foregroundColor(.blue)
        }
        .ignoresSafeArea() // 先让VStack占满全屏,后续单独处理安全区
    }
}

之后boardSize变量就会存储棋盘的实际宽高,游戏逻辑直接用这个变量就行。

二、安全区适配(刘海/非刘海设备自动兼容)

你之前用UIScreen.main.bounds.height出现位置偏移,是因为这个值包含了屏幕全部高度(包括刘海、底部小黑条这类安全区外区域)。正确做法是用GeometryReader获取带安全区信息的布局上下文:

struct GameView: View {
    @State private var boardSize: CGSize = .zero
    
    var body: some View {
        GeometryReader { screenProxy in
            VStack(spacing: 0) {
                // 顶部矩形:自动适配顶部安全区
                Rectangle()
                    .frame(height: 140)
                    .foregroundColor(.red)
                
                // 中间棋盘:填充安全区内的剩余空间
                Rectangle()
                    .foregroundColor(.green)
                    .frame(height: screenProxy.size.height - 140 - 140 - screenProxy.safeAreaInsets.top - screenProxy.safeAreaInsets.bottom)
                    .background(
                        GeometryReader { proxy in
                            Color.clear
                                .onAppear { boardSize = proxy.size }
                        }
                    )
                
                // 底部矩形:自动适配底部安全区
                Rectangle()
                    .frame(height: 140)
                    .foregroundColor(.blue)
            }
            // 给VStack加安全区padding,自动适配刘海/非刘海设备
            .padding(.top, screenProxy.safeAreaInsets.top)
            .padding(.bottom, screenProxy.safeAreaInsets.bottom)
        }
        .ignoresSafeArea()
    }
}

关键说明:

  • screenProxy.safeAreaInsets会自动识别设备:刘海设备返回顶部/底部安全区间距,非刘海设备返回0,不用额外判断。
  • 中间棋盘高度计算:用屏幕总高度减去上下固定矩形高度,再减去安全区上下间距,确保刚好填充剩余可用空间。
  • 要是想让顶部/底部矩形直接贴屏幕边缘(包括安全区外),去掉.padding(.top/.bottom)就行,但刘海设备上顶部矩形会被遮挡,按需选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 16:23:36