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

SwiftUI列表快速滚动/拖拽报错及标题动画卡顿问题求助

SwiftUI列表滚动异常问题修复

问题现象

  1. 快速滚动列表或多次上下拖拽时,触发Invalid sample AnimatablePair...错误,提示时间戳异常
  2. 顶部"Scroll Up or down"关联的标题字体动画卡顿、不流畅

问题根源

  1. 手势冲突:自定义DragGesture通过simultaneousGesture绑定到List,与List原生滚动手势同时触发,导致动画系统接收到时序混乱的帧数据,抛出时间戳错误
  2. 状态频繁更新:DragGesture.onChanged每帧都会触发,频繁更新isUp状态,导致动画被反复打断,出现卡顿

修复方案及代码

import SwiftUI

struct ContentView: View {
    @State var items = listData
    
    @State var isUp: Bool = true
    @State var initialDragDirection: Bool?
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(items) { item in
                    Text(item.title)
                }
            }
            .padding(.vertical)
            // 替换simultaneousGesture为普通gesture,设置最小拖拽距离过滤无效操作
            .gesture(
                DragGesture(minimumDistance: 5)
                    .onChanged { value in
                        // 用拖拽偏移量判断方向,比实时位置更准确
                        let currentDirection = value.translation.y < 0
                        
                        // 仅在拖拽方向明确且持续时更新状态,避免频繁切换
                        if initialDragDirection == nil {
                            initialDragDirection = currentDirection
                        } else if initialDragDirection == currentDirection {
                            isUp = currentDirection
                        }
                    }
                    .onEnded { _ in
                        initialDragDirection = nil
                    }
            )
            .listStyle(.plain)
            .toolbarBackground(.hidden, for: .navigationBar)
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Text("Scroll \(isUp ? "up" : "down")")
                }
            }
            .safeAreaInset(edge: .top, content: {
                VStack {
                    Text("John")
                        .font(isUp ? .title : .largeTitle)
                        .animation(.easeIn(duration: 0.2), value: isUp)
                    Text("Test")
                        .font(isUp ? .title : .largeTitle)
                        .animation(.easeIn(duration: 0.2), value: isUp)
                }
            })
        }
    }
}

#Preview {
    ContentView()
}

struct ContentItem: Identifiable {
    var id: UUID = UUID()
    var title: String
}

var listItems = Array(repeating: "Hello", count: 100)
var listData = listItems.map { ContentItem(title: $0) }

修复说明

  • 移除simultaneousGesture避免与List原生滚动手势冲突,设置minimumDistance: 5过滤微小滑动,减少无效状态更新
  • 使用translation.y判断拖拽方向(偏移量<0为向上滑),比实时location.y更稳定,不受屏幕位置影响
  • 新增initialDragDirection变量,确保只有当拖拽方向明确且持续时才更新isUp,避免快速滚动时的方向频繁切换
  • 将动画直接绑定到font属性上,而非容器视图,让动画系统更高效处理属性变化,提升流畅度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:04:55