SwiftUI分页TabView如何自适应内容高度 无需设置固定frame
自适应内容高度的分页TabView解决方案
核心原理是通过SwiftUI的PreferenceKey机制动态捕获Tab内容的实际高度,限制TabView的尺寸,避免其默认撑满全屏:
import SwiftUI struct ViewHeightKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { // 取所有Tab项的最大高度,避免切换页面时高度跳动 value = max(value, nextValue()) } } struct Test: View { struct Entry: Identifiable { let image: Image let description: String var id: String { description } } let data = [ Entry(image: Image(systemName: "scribble"), description: "image 1"), Entry(image: Image(systemName: "trash"), description: "image 2") ] // 存储内容实际高度 @State private var tabContentHeight: CGFloat = 0 var body: some View { ZStack(alignment: .topTrailing) { TabView { ForEach(data) { entry in VStack { entry.image .resizable() .scaledToFit() .frame(maxWidth: .infinity) Text(entry.description) } // 捕获当前Tab项的高度 .background(GeometryReader { proxy in Color.clear.preference(key: ViewHeightKey.self, value: proxy.size.height) }) } } .tabViewStyle(.page(indexDisplayMode: .never)) // 绑定TabView高度为内容实际高度 .frame(height: tabContentHeight) // 监听内容高度变化 .onPreferenceChange(ViewHeightKey.self) { height in tabContentHeight = height } Color.red .frame(width: 20, height: 20) } } }
可选优化
如果不同Tab项的内容高度差异较大,又希望短内容顶部对齐而非居中,可以给Tab内部的VStack添加如下修饰符:
.frame(maxHeight: .infinity, alignment: .top)
内容的提问来源于stack exchange,提问作者Ella Gogo
相关产品推荐
相关产品推荐

