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

SwiftUI拖拽手势与contentTransition异常:拖拽时文本跳帧卡顿

问题原因及解决方案

问题根源

  1. 动画上下文冲突:在拖拽手势的onChanged中用withAnimation包裹offset更新,会让整个视图进入动画状态,和文本的numericText过渡动画互相干扰,导致文本更新时跳帧卡顿。
  2. 冗余手势判断:原代码里对水平滑动的分支处理完全是无用逻辑,无意义的判断会增加额外计算开销。

修复步骤

  • 移除onDrag里的withAnimation:拖拽是实时交互操作,直接更新offset即可,不需要额外添加动画包裹
  • 简化手势判断逻辑,砍掉无用的水平滑动分支
  • (可选)给文本的数字过渡指定显式动画,避免和其他隐式动画冲突

修改后的完整代码

struct ContentView: View {
    @State var offset : CGFloat = 0
    @State var time: String = "0.0"
    let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()

    var body: some View {
      VStack {
        Spacer()
        Text(time)
          .contentTransition(.numericText())
          .onReceive(timer) { value in
            // 指定显式动画,避免和其他动画冲突
            withAnimation(.linear(duration: 0.1)) {
              time = value.timeIntervalSince1970.minuteSecond
            }
          }
        Spacer()
      }
      .frame(maxWidth: .infinity)
      .background(.red)
      .offset(y: offset)
      .gesture(swipeDownGesture)
    }
}

extension ContentView {
  var swipeDownGesture: some Gesture {
    DragGesture()
      .onChanged(onDrag(value:))
      .onEnded(onSwipeDownEnded(value:))
  }

  func onDrag(value: DragGesture.Value){
      let verticalAmount = value.translation.height
      // 仅处理向下拖拽的情况,直接更新offset
      if verticalAmount > 0 {
        offset = verticalAmount
      }
  }

  func onSwipeDownEnded(value: DragGesture.Value){
    withAnimation(.smooth(duration: 0.32, extraBounce: 0.22)) {
      offset = 0
    }
  }
}

额外说明

  • 拖拽时实时更新offset是原生交互反馈,不需要动画,动画只在拖拽结束的复位阶段添加即可
  • 给文本数字过渡指定和定时器间隔匹配的线性动画,能让数字变化更平滑,避免和其他动画上下文冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 11:36:01