SwiftUI底部Sheet内嵌ScrollView滚动触发关闭问题求助
SwiftUI Bottom Sheet嵌入ScrollView时阻止顶部滚动触发Sheet关闭
问题场景
在SwiftUI的Bottom Sheet中嵌入ScrollView后,滚动ScrollView至顶部并继续向上拖拽时,会触发Bottom Sheet的关闭操作,希望仅让ScrollView响应滚动及回弹,不影响Bottom Sheet的显示状态。已尝试exclusively、simultaneous手势选项及highPriorityGesture,但未解决问题。
解决方案
通过给Bottom Sheet的内容添加gesture(DragGesture(), including: .subviews),让子视图(即ScrollView)优先响应拖拽手势,避免手势传递给Bottom Sheet的关闭逻辑。如果需要保留Bottom Sheet的手动拖拽关闭功能,可以结合ScrollView的滚动状态判断来动态启用/禁用交互关闭。
基础修复代码(直接阻止Sheet响应拖拽)
struct ExampleView: View { @State private var showSheet = false var body: some View { NavigationView { VStack(spacing: 20) { Button("Show Bottom Sheet") { showSheet.toggle() } .buttonStyle(.borderedProminent) .sheet(isPresented: $showSheet) { BottomSheetView() .presentationDetents([.medium]) .ignoresSafeArea() // 让子视图优先响应拖拽手势,屏蔽Sheet的关闭触发 .gesture(DragGesture(), including: .subviews) } } } } } // 示例BottomSheetView实现 struct BottomSheetView: View { var body: some View { ScrollView { LazyVStack(spacing: 16) { ForEach(1...50, id: \.self) { index in Text("列表项 \(index)") .frame(maxWidth: .infinity) .padding() .background(Color.gray.opacity(0.2)) .cornerRadius(8) } } .padding() } .background(Color.white) } }
进阶方案(动态保留Sheet拖拽关闭功能)
如果需要仅在ScrollView无法继续滚动时(已到顶部)才允许关闭Sheet,可以通过监听ScrollView滚动偏移量,动态控制交互关闭状态:
struct ExampleView: View { @State private var showSheet = false var body: some View { NavigationView { VStack(spacing: 20) { Button("Show Bottom Sheet") { showSheet.toggle() } .buttonStyle(.borderedProminent) .sheet(isPresented: $showSheet) { BottomSheetView() .presentationDetents([.medium]) .ignoresSafeArea() } } } } } struct BottomSheetView: View { // 跟踪ScrollView的滚动偏移量 @State private var scrollOffset: CGFloat = 0 var body: some View { ScrollView { LazyVStack(spacing: 16) { ForEach(1...50, id: \.self) { index in Text("列表项 \(index)") .frame(maxWidth: .infinity) .padding() .background(Color.gray.opacity(0.2)) .cornerRadius(8) } } .padding() .background( GeometryReader { proxy in Color.clear .preference(key: ScrollOffsetKey.self, value: proxy.frame(in: .named("scrollView")).minY) } ) } .coordinateSpace(name: "scrollView") .onPreferenceChange(ScrollOffsetKey.self) { value in scrollOffset = value } .background(Color.white) // 当ScrollView未滚动到顶部时,禁用Sheet的交互关闭 .interactiveDismissDisabled(scrollOffset > 0) } } // 自定义PreferenceKey用于监听滚动偏移 struct ScrollOffsetKey: PreferenceKey { static var defaultValue: CGFloat = 0 static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {} }
内容的提问来源于stack exchange,提问作者MrGarlic
相关产品推荐
相关产品推荐

