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

macOS下SwiftUI嵌套ScrollView水平滚动卡顿问题求助

macOS SwiftUI 嵌套ScrollView滚动异常解决方案

针对水平ScrollView嵌套垂直ScrollView时,macOS下水平滚动鼠标下方内容冻结的问题,以下是几个可行的解决方案:

1. 手动控制内层ScrollView的手势响应

通过onHover和手势修饰符,在鼠标悬停内层垂直ScrollView时,临时让外层水平ScrollView优先处理滚动事件:

@State private var enableInnerScroll = true

ScrollView(.horizontal) {
    HStack(spacing: 20) {
        ForEach(0..<10) { index in
            ScrollView(.vertical) {
                VStack(spacing: 10) {
                    ForEach(0..<20) { row in
                        Text("Item \(index)-\(row)")
                            .frame(width: 200, height: 50)
                            .background(Color.gray.opacity(0.2))
                    }
                }
            }
            .onHover { isHovered in
                enableInnerScroll = isHovered
            }
            .gesture(
                DragGesture()
                    .onChanged { _ in
                        guard enableInnerScroll else { return }
                        // 仅当允许内层滚动时才处理手势
                    }
            )
        }
    }
}

2. 用AppKit的NSScrollView替代内层SwiftUI ScrollView

利用SwiftUI与AppKit的互操作,用原生NSScrollView实现垂直滚动,避免手势冲突:

struct AppKitVerticalScroll<Content: View>: NSViewRepresentable {
    let content: Content
    
    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }
    
    func makeNSView(context: Context) -> NSScrollView {
        let scrollView = NSScrollView()
        scrollView.hasVerticalScroller = true
        scrollView.hasHorizontalScroller = false
        scrollView.autohidesScrollers = true
        scrollView.documentView = NSHostingView(rootView: content)
        return scrollView
    }
    
    func updateNSView(_ nsView: NSScrollView, context: Context) {
        (nsView.documentView as? NSHostingView<Content>)?.rootView = content
    }
}

// 使用示例
ScrollView(.horizontal) {
    HStack(spacing: 20) {
        ForEach(0..<10) { index in
            AppKitVerticalScroll {
                VStack(spacing: 10) {
                    ForEach(0..<20) { row in
                        Text("Item \(index)-\(row)")
                            .frame(width: 200, height: 50)
                            .background(Color.gray.opacity(0.2))
                    }
                }
            }
            .frame(width: 200)
        }
    }
}

3. 区分ScrollView的坐标空间

给外层和内层ScrollView指定独立的命名坐标空间,帮助SwiftUI正确识别手势的目标视图:

ScrollView(.horizontal, coordinateSpace: .named("OuterHorizontal")) {
    HStack(spacing: 20) {
        ForEach(0..<10) { index in
            ScrollView(.vertical, coordinateSpace: .named("InnerVertical-\(index)")) {
                VStack(spacing: 10) {
                    ForEach(0..<20) { row in
                        Text("Item \(index)-\(row)")
                            .frame(width: 200, height: 50)
                            .background(Color.gray.opacity(0.2))
                    }
                }
            }
            .frame(width: 200)
        }
    }
}

4. 滚动时动态禁用内层ScrollView

检测水平滚动状态,在滚动过程中禁用内层垂直ScrollView,滚动结束后恢复:

@State private var isHorizontalScrolling = false

ScrollView(.horizontal) {
    HStack(spacing: 20) {
        ForEach(0..<10) { index in
            ScrollView(.vertical) {
                VStack(spacing: 10) {
                    ForEach(0..<20) { row in
                        Text("Item \(index)-\(row)")
                            .frame(width: 200, height: 50)
                            .background(Color.gray.opacity(0.2))
                    }
                }
            }
            .disabled(isHorizontalScrolling)
            .frame(width: 200)
        }
    }
}
.gesture(
    DragGesture(minimumDistance: 5)
        .onChanged { value in
            // 判断滚动方向,优先响应水平滚动
            if abs(value.translation.width) > abs(value.translation.height) {
                isHorizontalScrolling = true
            }
        }
        .onEnded { _ in
            isHorizontalScrolling = false
        }
)

内容的提问来源于stack exchange,提问作者Max Gribov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:41:06