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
相关产品推荐
相关产品推荐

