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

SwiftUI中为ScrollView滑至末端并继续拖拽添加触发动作

SwiftUI水平ScrollView实现反向拖拽触发加载功能

完全可以实现类似反向“下拉刷新”的功能——比如在水平ScrollView滚动到最左端后继续向左拖拽时触发加载动作。核心思路是结合滚动位置检测和拖拽手势识别,以下是具体实现方案:

实现步骤与代码示例

我们以你的现有代码为基础,结合ScrollViewReader和DragGesture来完成功能:

1. 完善ViewModel逻辑

首先在你的ViewModel中添加加载状态和数据加载方法:

class YourViewModel: ObservableObject {
    @Published var recomendations: [Recommendation] = []
    @Published var isLoading = false
    
    // 初始加载数据
    func loadInitialData() {
        // 替换为你的真实数据请求逻辑
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.recomendations = (1...10).map { Recommendation(placeID: $0, name: "推荐地点 \($0)") }
        }
    }
    
    // 加载更多数据(从左侧插入)
    func loadMoreData() {
        guard !isLoading else { return }
        isLoading = true
        // 替换为你的真实数据请求逻辑
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
            let newRecommendations = (11...20).map { Recommendation(placeID: $0, name: "推荐地点 \($0)") }
            self.recomendations.insert(contentsOf: newRecommendations, at: 0)
            self.isLoading = false
        }
    }
}

// 你的数据模型示例
struct Recommendation: Identifiable {
    let id = UUID()
    let placeID: Int
    let name: String
}

2. 修改View层代码

在View中集成滚动检测和拖拽手势:

struct ContentView: View {
    @StateObject var viewModel = YourViewModel()
    @State private var isAtLeftEdge = false
    
    var body: some View {
        ScrollViewReader { proxy in
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 15) {
                    // 左侧加载指示器
                    if viewModel.isLoading {
                        ProgressView()
                            .frame(width: 80, height: 100)
                            .id("loadingIndicator")
                    }
                    
                    // 原有列表内容
                    ForEach(viewModel.recomendations, id: \.placeID) { rec in
                        // 替换为你的自定义单元格视图
                        Text(rec.name)
                            .frame(width: 120, height: 100)
                            .background(Color.gray.opacity(0.2))
                            .cornerRadius(8)
                    }
                }
                .padding(.horizontal)
                // 检测是否滚动到最左端
                .onScrollChange { scrollPhase in
                    isAtLeftEdge = scrollPhase.isScrolling && scrollPhase.contentOffset.width <= 0
                }
            }
            // 添加拖拽手势监听
            .gesture(
                DragGesture(minimumDistance: 15)
                    .onEnded { value in
                        // 满足条件时触发加载:向左拖拽超过阈值+在最左端+未加载中
                        let dragThreshold: CGFloat = -50
                        if value.translation.width < dragThreshold && isAtLeftEdge && !viewModel.isLoading {
                            viewModel.loadMoreData()
                            // 可选:滚动到加载指示器位置
                            withAnimation {
                                proxy.scrollTo("loadingIndicator", anchor: .leading)
                            }
                        }
                    }
            )
            .onAppear {
                viewModel.loadInitialData()
            }
        }
    }
}

关键说明

  • 滚动位置检测:通过onScrollChange回调获取滚动偏移量,判断是否到达ScrollView最左端(contentOffset.width <= 0)
  • 拖拽触发逻辑:利用DragGesture监听向左拖拽的动作,当拖拽距离超过设定阈值(比如-50)时,触发加载方法
  • 数据插入位置:因为是从左侧加载新内容,所以将新数据插入到数组开头
  • 用户体验优化:添加加载指示器,让用户清晰感知加载状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 09:05:33