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
相关产品推荐
相关产品推荐

