SwiftUI 中如何禁止 ScrollView 滚动超过指定的顶部边界位置
实现方案
你需要限制ScrollView的顶部滚动偏移,禁止下拉时内容超过顶部边界,根据你支持的iOS版本可以选择不同实现方式:
方案1:iOS 16+ 最简原生实现
直接使用系统提供的scrollBounceBehavior修饰符即可实现效果,代码改动最小:
import SwiftUI struct ScrollViewIssue: View { var body: some View { ScrollView { VStack { Rectangle() .foregroundColor(.gray) .frame(height: 200) Circle() .frame(width: 300, height: 300) Circle() .frame(width: 300, height: 300) Circle() .frame(width: 300, height: 300) Circle() .frame(width: 300, height: 300) } } // 禁用垂直方向顶部弹跳效果 .scrollBounceBehavior(.basedOnSize, axes: .vertical) .ignoresSafeArea() } }
方案2:全iOS版本兼容实现
如果需要支持iOS15及更低版本,可以通过桥接底层UIScrollView,在滚动代理中强制限制顶部偏移量:
import SwiftUI import UIKit struct NoTopBounceScrollView<Content: View>: UIViewRepresentable { let content: Content init(@ViewBuilder content: () -> Content) { self.content = content() } func makeUIView(context: Context) -> UIScrollView { let scrollView = UIScrollView() scrollView.delegate = context.coordinator scrollView.showsVerticalScrollIndicator = true let hostingView = UIHostingController(rootView: content).view! hostingView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(hostingView) NSLayoutConstraint.activate([ hostingView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor), hostingView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor), hostingView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor), hostingView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor), hostingView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor) ]) return scrollView } func updateUIView(_ uiView: UIScrollView, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator: NSObject, UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { // 强制限制顶部偏移,禁止下拉超过内容顶部 if scrollView.contentOffset.y < 0 { scrollView.contentOffset.y = 0 } } } } // 业务层调用代码 struct ScrollViewIssue: View { var body: some View { NoTopBounceScrollView { VStack { Rectangle() .foregroundColor(.gray) .frame(height: 200) Circle() .frame(width: 300, height: 300) Circle() .frame(width: 300, height: 300) Circle() .frame(width: 300, height: 300) Circle() .frame(width: 300, height: 300) } } .ignoresSafeArea() } }
内容的提问来源于stack exchange,提问作者SmoothPoop69
相关产品推荐
相关产品推荐

