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

