SwiftUI中ScrollView与fixedSize修饰符的布局问题
问题解决:ScrollView展开时不挤压底部按钮
问题分析
你的问题根源在于ScrollView使用了.fixedSize(vertical: true)修饰符——这个属性会让ScrollView的高度完全跟随内容动态变化,当展开的内容高度超过屏幕剩余空间时,就会把底部的Add按钮挤出屏幕,而且因为ScrollView本身没有高度限制,也不会触发内部滚动。
解决方案
只需要调整两处:
- 移除ScrollView的
.fixedSize(horizontal: false, vertical: true) - 给ScrollView添加
.frame(maxHeight: .infinity),让它占据VStack中除Add按钮外的所有可用空间,内容超出时ScrollView内部滚动,不会挤压底部按钮 - 移除VStack中的
Spacer(),避免ScrollView被向上推挤
修改后的完整代码
struct ContentView: View { var body: some View { VStack(spacing: 8) { ScrollView { ExpandView() } .frame(maxHeight: .infinity) // 让ScrollView填充剩余空间 Button { } label: { HStack { Spacer() Text("Add") Spacer() } .background(Color.green) } } .frame(maxWidth: .infinity) // 可选:适配底部安全区,避免按钮被遮挡(iOS 15+可用) .padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0) } } struct ExpandView: View { var body: some View { VStack { Accordion(title: "Red", content: { Rectangle() .fill(.red) .frame(height: 600) }) Accordion(title: "Blue", content: { Rectangle() .fill(.blue) .frame(height: 600) }) } } } struct Accordion<Content: View>: View { @State var isExpand: Bool = false let title: String @ViewBuilder let content: Content var body: some View { VStack(spacing: 0) { Button(action: { withAnimation { isExpand.toggle() } }, label: { HStack { Spacer() Text(title) Spacer() } }) .buttonStyle(.plain) .frame(height: 44) .background(Color.yellow) if isExpand { content .padding(.horizontal, 12) .transition(.move(edge: .top)) } } .clipped() } }
效果说明
修改后,ScrollView会自动占据Add按钮上方的所有可用空间,当展开的内容高度超过这个空间时,ScrollView会启用内部滚动,底部的Add按钮将始终固定在屏幕底部,不会被挤压出去。
内容的提问来源于stack exchange,提问作者duckSern1108
相关产品推荐
相关产品推荐

