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

SwiftUI中如何检测用户滚动至屏幕底部并触发函数

在SwiftUI中检测滚动至屏幕底部并触发函数的最佳方案

你当前的代码问题在于GeometryReader的位置不对——它被放在了ScrollView外面,获取的是父视图的frame,无法正确捕捉滚动内容的底部位置。下面是几种可靠的实现方式:

方法一:在滚动内容末尾添加检测视图(推荐适配LazyVGrid)

在你的LazyVGrid后面添加一个不可见的占位视图,用GeometryReader检测它是否进入可视区域,以此判断是否滚动到了底部:

var body: some View {
    NavigationView {
        VStack {
            ZStack {
                Text("Pokedex")
                    .font(.custom("Pokemon Solid", size: 25))
                    .foregroundColor(.yellow)
                    .opacity(0.3)
                
                ScrollView {
                    LazyVGrid(columns: adaptiveColumns, spacing: 5) {
                        ForEach(viewModel.filteredPokemon) { pokemon in
                            NavigationLink(destination: PokemonDetailView(pokemon: pokemon)) {
                                PokemonView(vm: viewModel, pokemon: pokemon)
                            }
                        }
                    }
                    .animation(.easeInOut(duration: 0.3), value: viewModel.filteredPokemon.count)
                    
                    // 底部检测视图
                    Color.clear
                        .frame(height: 1)
                        .background(
                            GeometryReader { proxy in
                                Color.clear
                                    .onAppear {
                                        let bottomViewTopEdge = proxy.frame(in: .global).minY
                                        let screenHeight = UIScreen.main.bounds.height
                                        // 当底部视图顶部进入屏幕时,触发加载
                                        if bottomViewTopEdge < screenHeight {
                                            // 加加载状态防止重复触发
                                            if !viewModel.isLoading {
                                                viewModel.loadMorePokemon() // 你的加载函数
                                            }
                                        }
                                    }
                            }
                        )
                }
                .navigationTitle("Pokedexarino")
                .navigationBarTitleDisplayMode(.inline)
                .searchable(text: $viewModel.searchText)
            }
        }
    }
    .environmentObject(viewModel)
}

方法二:监听UIScrollView滚动通知

利用SwiftUI底层的UIScrollView通知,直接判断滚动偏移量:

var body: some View {
    NavigationView {
        VStack {
            ZStack {
                Text("Pokedex")
                    .font(.custom("Pokemon Solid", size: 25))
                    .foregroundColor(.yellow)
                    .opacity(0.3)
                
                ScrollView {
                    LazyVGrid(columns: adaptiveColumns, spacing: 5) {
                        ForEach(viewModel.filteredPokemon) { pokemon in
                            NavigationLink(destination: PokemonDetailView(pokemon: pokemon)) {
                                PokemonView(vm: viewModel, pokemon: pokemon)
                            }
                        }
                    }
                    .animation(.easeInOut(duration: 0.3), value: viewModel.filteredPokemon.count)
                }
                .navigationTitle("Pokedexarino")
                .navigationBarTitleDisplayMode(.inline)
                .searchable(text: $viewModel.searchText)
                // 监听滚动通知
                .onReceive(NotificationCenter.default.publisher(for: UIScrollView.didScrollNotification)) { notification in
                    guard let scrollView = notification.object as? UIScrollView else { return }
                    let offsetY = scrollView.contentOffset.y
                    let contentTotalHeight = scrollView.contentSize.height
                    let scrollViewFrameHeight = scrollView.frame.size.height
                    
                    // 提前100px触发加载(可调整阈值)
                    let triggerThreshold: CGFloat = 100
                    if offsetY > contentTotalHeight - scrollViewFrameHeight - triggerThreshold {
                        if !viewModel.isLoading {
                            viewModel.loadMorePokemon()
                        }
                    }
                }
            }
        }
    }
    .environmentObject(viewModel)
}

关键注意点

  • 必须添加加载状态标记(比如isLoading),避免滚动时重复触发加载函数
  • 方法一更适配LazyVGrid这类懒加载容器,因为它依赖内容的可见性;方法二则适合所有ScrollView场景
  • 可以调整触发阈值(比如提前加载),让用户在滚动到底部前就开始加载内容,提升体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 23:20:38