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

iOS16+下SwiftUI List结合ScrollViewReader滚动崩溃求解决方案

iOS16+ SwiftUI List滚动崩溃问题解决方案

在iOS16及以上版本中,使用ScrollViewReader配合List滚动到指定Section时出现崩溃,替换为LazyVStack可正常运行,以下是几个可行修复方案:

  • 延迟滚动操作,确保List完全渲染
    iOS16+中List的Section渲染时机发生了变化,直接在onAppear中调用scrollTo可能触发视图未初始化的崩溃。通过延迟执行滚动,给List足够的渲染时间:

    .onAppear(perform: {
        guard viewModel.newSections.contains("Today/Ongoing"),
              viewModel.newRowsPerSection["Today/Ongoing"]?.count ?? 0 > 0 else { return }
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            proxy.scrollTo("Today/Ongoing", anchor: .topLeading)
        }
    })
    
  • 给Section设置更稳定的唯一标识
    原代码直接用sectionName作为Section的id,数据更新时可能出现标识冲突或视图状态混乱。可以给id添加固定后缀,保证唯一性:

    Section(header: VStack { LeaguesScheduleListSectionView(text: sectionName) }) {
        // 行内容
    }
    .id("\(sectionName)_section")
    

    滚动时同步修改目标id:

    proxy.scrollTo("Today/Ongoing_section", anchor: .topLeading)
    
  • 监听数据加载完成事件,替代onAppear触发滚动
    原代码依赖onAppear触发滚动,但API数据加载完成时机可能晚于视图出现。在ViewModel中添加数据加载完成状态,监听该状态再执行滚动:

    // 在ContentViewModel中添加
    @Published var dataLoaded = false
    
    // 数据加载完成后设置dataLoaded = true
    
    // 在ContentView中监听
    .onChange(of: viewModel.dataLoaded) { loaded in
        guard loaded,
              viewModel.newSections.contains("Today/Ongoing"),
              viewModel.newRowsPerSection["Today/Ongoing"]?.count ?? 0 > 0 else { return }
        proxy.scrollTo("Today/Ongoing", anchor: .topLeading)
    }
    
  • 使用iOS16+新增的List原生滚动方法
    iOS16及以上版本的List支持直接绑定滚动目标,无需依赖ScrollViewReader,可以尝试这种原生方案:

    struct ContentView: View {
        @StateObject var viewModel: ContentViewModel
        @State private var scrollTarget: String?
    
        var body: some View {
            List {
                ForEach(Array(viewModel.newSections), id: \.self) { sectionName in
                    Section(header: VStack { LeaguesScheduleListSectionView(text: sectionName) }) {
                        ForEach(viewModel.newRowsPerSection[sectionName] ?? []) { leagueScheduleEvent in
                            LeaguesScheduleListRowView(leagueSchedule: leagueScheduleEvent)
                        }
                    }
                    .id(sectionName)
                }
            }
            .listStyle(.plain)
            .scrollTo(scrollTarget, anchor: .topLeading)
            .onAppear {
                if viewModel.newSections.contains("Today/Ongoing"),
                   viewModel.newRowsPerSection["Today/Ongoing"]?.count ?? 0 > 0 {
                    scrollTarget = "Today/Ongoing"
                }
            }
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 18:05:31