SwiftUI:如何让PlaceholderView占满ScrollView头部外的剩余空间?
SwiftUI中让PlaceholderView在头部下方剩余空间居中的实现方案
核心思路
通过捕获顶部HStack的实际高度,计算屏幕总高度与头部高度的差值,将该差值设为PlaceholderView的高度,同时确保PlaceholderView内部内容在该高度范围内垂直居中。
具体实现步骤
- 定义PreferenceKey捕获视图高度
创建自定义PreferenceKey,用于传递HStack的高度值:
struct ViewHeightKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value = nextValue() } }
- 捕获HStack的实际高度并计算剩余空间
在头部HStack上添加背景视图,通过GeometryReader读取其高度,再用屏幕总高度减去该值得到PlaceholderView的目标高度:
@State private var headerHeight: CGFloat = 0 var body: some View { GeometryReader { geometry in ScrollView { HStack(spacing: .zero) { Text("This is my greeting to you") Spacer() } .background( GeometryReader { proxy in Color.clear .preference(key: ViewHeightKey.self, value: proxy.size.height) } ) .onPreferenceChange(ViewHeightKey.self) { newHeight in headerHeight = newHeight } if greetings.isEmpty { PlaceholderView() .frame(height: geometry.size.height - headerHeight) .frame(maxWidth: .infinity) } else { LazyVStack { ForEach(greetings, id: \.self) { greeting in Text(greeting) } } } } } }
- 调整PlaceholderView内部布局
修改PlaceholderView,让其内部内容在分配的高度范围内垂直居中:
struct PlaceholderView: View { var body: some View { VStack { Image(systemName: "hand.wave") Text("Hello world!") } .frame(maxHeight: .infinity) } }
原理说明
- PreferenceKey用于在视图层级间传递HStack的实际渲染高度,避免硬编码或估算高度带来的误差。
- 用屏幕总高度减去头部高度得到的剩余空间,刚好是HStack下方的可用区域,将其设为PlaceholderView的高度,确保占位视图不会超出或不足该区域。
- 给PlaceholderView内部的VStack设置
maxHeight: .infinity,让其在父视图高度范围内自动实现垂直居中。
内容的提问来源于stack exchange,提问作者lazarevzubov
相关产品推荐
相关产品推荐

