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

使用UIViewPropertyAnimator实现视图抖动时振幅过小如何修复

Bug 原因

你写的动画振幅不达预期的核心原因是 UIViewPropertyAnimator 默认将多个添加的动画作为加性动画处理,多个位移动画的变化量会叠加计算,而非按你预期的顺序依次替换视图位置。同时你每个动画块都基于视图初始center设置位移,叠加后实际的偏移量远低于你设定的数值。

修复方案

推荐使用关键帧动画实现更稳定的序列位移效果,修复后代码如下:

func shake(_ completion: @escaping () -> Void) {
    // 提前保存初始位置,避免动画过程中值变化
    let originalCenter = self.center
    let animator = UIViewPropertyAnimator(duration: 0.6, curve: .linear)
    
    animator.addAnimations {
        UIView.animateKeyframes(
            withDuration: 0.6,
            delay: 0,
            options: .calculationModeLinear
        ) {
            let distances: [CGFloat] = [-20.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ]
            let stepCount = Double(distances.count)
            
            for (i, value) in distances.enumerated() {
                let startTime = Double(i) / stepCount
                let duration = 1.0 / stepCount
                UIView.addKeyframe(
                    withRelativeStartTime: startTime,
                    relativeDuration: duration
                ) {
                    self.center = CGPoint(x: originalCenter.x + value, y: originalCenter.y)
                }
            }
        }
    }
    
    animator.addCompletion { _ in completion() }
    animator.startAnimation()
}

如果需要保留原有分段添加动画的写法,可以在添加动画时指定配置项禁用加性逻辑:

func shake(_ completion: @escaping () -> Void) {
    let originalCenter = self.center
    let animator = UIViewPropertyAnimator(duration: 0.6, curve: .linear)
    let distances: [CGFloat] = [-20.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ]
    
    for (i, value) in distances.enumerated() {
        let delayFactor = Double(i) / Double(distances.count)
        animator.addAnimations(
            { [weak self] in
                self?.center = CGPoint(x: originalCenter.x + value, y: originalCenter.y)
            },
            delayFactor: CGFloat(delayFactor),
            animationOptions: [.overrideInheritedOptions, .beginFromCurrentState]
        )
    }
    
    animator.addCompletion { _ in completion() }
    animator.startAnimation()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 02:18:03