You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 01:35:23