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

SwiftUI获取动画移动中View的实时坐标时onChange不触发如何解决

onChange 未触发的根本原因

  • 你监听的是Position类的实例P本身,作为引用类型,它的内存地址自始至终没有变化,onChange检测不到实例内部属性的变更,所以永远不会触发回调。
  • 退一步说,就算你改为监听P.xObjective这类属性,也只能拿到动画结束后的目标坐标,拿不到动画过程中的实时值:SwiftUI的动画在渲染层执行,状态值xObjective/yObjective会直接被设置为目标值,你通过状态读不到中间过渡坐标。
  • 额外说明:你给Position加的Equatable实现完全没有作用,可以直接移除。

实时获取动画中坐标的正确方案

使用AnimatableModifier实现坐标实时采集:它的animatableData属性会在动画每帧更新时同步回调,采样频率和屏幕刷新率一致,完全满足你15-30次/秒的需求。

第一步:实现实时坐标采集的自定义Modifier

struct RealtimePositionModifier: AnimatableModifier {
    var targetX: CGFloat
    var targetY: CGFloat
    let onUpdate: (CGFloat, CGFloat) -> Void
    
    // 动画过程中每帧都会更新这个属性
    var animatableData: AnimatablePair<CGFloat, CGFloat> {
        get { AnimatablePair(targetX, targetY) }
        set {
            targetX = newValue.first
            targetY = newValue.second
            onUpdate(targetX, targetY)
        }
    }
    
    func body(content: Content) -> some View {
        content.position(x: targetX, y: targetY)
    }
}

第二步:修改Page视图代码,替换原有逻辑

struct Page: View {
    @ObservedObject var P: Position = Position()
    var body: some View {
        VStack {
            GeometryReader { geo in
                Point()
                    // 用自定义Modifier替代原生position
                    .modifier(RealtimePositionModifier(
                        targetX: P.xObjective,
                        targetY: P.yObjective,
                        onUpdate: { x, y in
                            // 这里的x、y就是动画过程中的实时全局坐标
                            P.xRealtime = x
                            P.yRealTime = y
                            print("实时坐标:X:\(x), Y:\(y)")
                        }
                    ))
                    // 明确指定动画触发条件,适配iOS15+的接口要求
                    .animation(.linear(duration: 0.2), value: P.xObjective)
                    .animation(.linear(duration: 0.2), value: P.yObjective)
            }
            Text("X: \(P.xRealtime), Y: \(P.yRealTime)")
        }.onAppear() {
            P.startMovement()
        }
    }
}

可选优化

如果不需要和屏幕刷新率一致的采样频率,可以在onUpdate回调里加时间过滤,比如每33ms才更新一次xRealtime/yRealTime,降低性能消耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 08:36:03