SwiftUI中如何让ScrollView自适应内容且无hack式实现最小占位
SwiftUI中双ScrollView的自适应高度布局需求
在SwiftUI中,ScrollView默认会占据所有可用空间,但我需要将两个ScrollView放置在VStack中,实现如下的自适应布局效果:

该示意图展示了三种核心状态:
- 两个ScrollView内容极少时,各自仅占据最小所需空间
- 第一个ScrollView内容较长时,它会占据更多空间,但保证第二个ScrollView完整显示
- 两个ScrollView内容均较长时,各占屏幕的50%空间
已尝试的实现方式
我找到了两种近似的实现思路:
- 第一种是在ScrollView背景添加
Color.clear,通过GeometryReader读取尺寸并更新@State变量,但这种方法不支持屏幕旋转,无法使用。 - 第二种使用PreferenceKey:同样在ScrollView的内容中添加
Color.clear背景,通过GeometryReader读取内容尺寸,再借助PreferenceKey传递尺寸值来调整ScrollView的高度。
疑问
这真的是唯一可行的实现方式吗?这种做法完全是hack式的!更不用说可能存在的性能问题了。
参考代码(第二种方案)
@main struct ThatApp: App { var body: some Scene { WindowGroup { ScrollsView() } } } struct ScrollViewHeightPreferenceKey: PreferenceKey { static var defaultValue: CGFloat = .zero static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { value += nextValue() } typealias Value = CGFloat } struct ScrollsView: View { var body: some View { VStack(spacing: 20) { ShrinkingScrollView(title: "First Scroll View", isLong: false) ShrinkingScrollView(title: "Second Scroll View", isLong: false) } .frame(width: 300) .background(Color.blue.opacity(0.3)) .padding() // just for beauty } } struct ShrinkingScrollView: View { let title: String let isLong: Bool //This will be the height of the ScrollView: @State private var height: CGFloat = .zero //Not important text string let string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." var body: some View { VStack(alignment: .leading) { Text(title) .fontWeight(.bold) ScrollView(.vertical, showsIndicators: true) { VStack(alignment: .leading, spacing: 10) { Text(string) if isLong { Text(string) Text(string) Text(string) } } .background { GeometryReader { geo in Color.clear .preference(key: ScrollViewHeightPreferenceKey.self, value: geo.size.height) } } } .onPreferenceChange(ScrollViewHeightPreferenceKey.self) { height = $0 } .frame(maxWidth: .infinity, maxHeight: height) .scrollBounceBehavior(.basedOnSize, axes: .vertical) //We are > iOS 16.4 .border(Color.red, width: 3) } } } #Preview { ScrollsView() }
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

