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

SwiftUI List中ProgressView首次加载后不再显示的问题求助

分页列表ProgressView无法重复显示的问题修复

问题根源

你的实现存在两个核心问题:

  1. 第一个方案中,.task修饰符仅在视图首次挂载时执行一次,后续即使滚动到底部,只要ProgressView没有被销毁重建,任务就不会再次触发。加上loadMore方法始终将hasMoreToLoad设为true,视图状态无变化,SwiftUI不会重新触发任务。
  2. 第二个方案用isLoading切换视图,加载完成后ProgressView被移除,没有了触发加载的入口,自然无法再次显示。

修复方案

方案1:基于onAppear的基础实现

通过onAppear监听ProgressView的出现,结合isLoading防止重复加载,确保每次滚动到底部时都能触发新的加载任务。

struct SomeView : View {
    @ObservedObject var viewModel = ViewModel()
    var body : some View {
        List {
            Section {
                ForEach(0..<viewModel.items.count) { i in
                    Text("\(viewModel.items[i])")
                        .frame(maxWidth: .infinity, alignment: .center)
                }
            }
            // 仅当还有数据可加载且未在加载时显示ProgressView
            if viewModel.hasMoreToLoad && !viewModel.isLoading {
                Section {
                    ProgressView()
                        .frame(maxWidth: .infinity, alignment: .center)
                        .onAppear {
                            Task { await viewModel.loadMore() }
                        }
                }
            }
        }
    }
}

class ViewModel : ObservableObject {
    @Published var items: [Int] = Array(0...10)
    @Published var hasMoreToLoad = true
    @Published var isLoading = false
    
    func loadMore() async {
        guard !isLoading else { return } // 阻止重复加载
        isLoading = true
        defer { isLoading = false } // 确保加载完成后重置状态
        
        // 模拟远程请求延迟
        await Task.sleep(for: Duration.milliseconds(500))
        
        // 添加新数据到列表
        let newItems = Array(items.count..<items.count+10)
        items.append(contentsOf: newItems)
        
        // 模拟无更多数据的场景(比如加载3次后停止)
        if items.count >= 40 {
            hasMoreToLoad = false
        }
    }
}

方案2:基于ScrollViewReader的精准监听

如果List的滚动触发不够灵敏,可使用ScrollViewReader主动监听最后一个列表项的可见状态,触发加载,这种方式更可靠。

struct SomeView : View {
    @ObservedObject var viewModel = ViewModel()
    var body : some View {
        List {
            Section {
                ForEach(0..<viewModel.items.count) { i in
                    Text("\(viewModel.items[i])")
                        .frame(maxWidth: .infinity, alignment: .center)
                        .id(i) // 为每个列表项设置唯一ID,用于滚动监听
                }
            }
            if viewModel.hasMoreToLoad {
                Section {
                    ProgressView()
                        .frame(maxWidth: .infinity, alignment: .center)
                        .id("loading") // 为加载视图设置ID
                }
            }
        }
        .scrollViewReader { proxy in
            // 监听列表项数量变化,检查最后一项是否可见
            .onChange(of: viewModel.items.count) { count in
                guard count > 0, viewModel.hasMoreToLoad, !viewModel.isLoading else { return }
                proxy.scrollTo(count - 1) { isVisible in
                    if isVisible {
                        Task { await viewModel.loadMore() }
                    }
                }
            }
            // 可选:加载新数据后自动滚动到加载视图,提升体验
            .onChange(of: viewModel.items) { _ in
                if viewModel.hasMoreToLoad {
                    proxy.scrollTo("loading", anchor: .bottom)
                }
            }
        }
    }
}

class ViewModel : ObservableObject {
    @Published var items: [Int] = Array(0...10)
    @Published var hasMoreToLoad = true
    @Published var isLoading = false
    
    func loadMore() async {
        guard !isLoading else { return }
        isLoading = true
        defer { isLoading = false }
        
        await Task.sleep(for: Duration.milliseconds(500))
        
        let newItems = Array(items.count..<items.count+10)
        items.append(contentsOf: newItems)
        
        if items.count >= 40 {
            hasMoreToLoad = false
        }
    }
}

核心注意事项

  • 一定要用isLoading状态做防重校验,避免多次重复请求服务器。
  • 当确认没有更多数据时,必须将hasMoreToLoad设为false,否则ProgressView会一直显示。
  • .task修饰符适用于一次性任务,分页加载需要重复触发,onAppear或滚动监听是更合适的选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 09:34:53