UIView.animate不生效问题:与animateKeyframes的表现差异排查
问题分析与解决方案
你猜的没错!问题确实出在你之前添加的CABasicAnimation上,它的配置直接导致了UIView.animate的隐式动画失效,让视图直接跳到了最终消失状态。
为什么两种动画表现差异这么大?
你给spinner的layer添加旋转动画时,设置了isRemovedOnCompletion = false和isCumulative = true,这会让这个动画永久附着在layer上,持续控制着transform.rotation.z的呈现状态。
- 对于
UIView.animate:它依赖UIKit的隐式动画系统,尝试给layer自动生成过渡动画来修改整个transform属性。但当layer上已经存在一个持久化的CA动画时,UIKit的隐式动画机制会被抑制——它无法在已有动画的基础上正确生成过渡逻辑,所以会直接将layer的实际属性值(modelLayer)设置为目标缩放状态,导致视图瞬间消失。 - 对于
UIView.animateKeyframes:它是显式创建并添加CAKeyframeAnimation到layer上,这种显式动画能绕过隐式动画的限制,直接强制执行过渡逻辑,所以能正常显示缩小过程。
如何用UIView.animate实现正常缩放?
最简单的解决办法就是在执行缩放动画前,先移除之前的旋转动画:
// 先移除旋转动画 self.spinnerImageView.layer.removeAnimation(forKey: self.spinnerAnimationKey) // 再执行UIView标准动画 UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveLinear, animations: { self.spinner.transform = CGAffineTransform(scaleX: 0.0, y: 0.0) }) { (_) in super.endRefreshing() }
额外建议:如果想保留旋转同时缩放
如果你希望在缩放过程中spinner还保持旋转,可以用CAAnimationGroup把两个动画组合起来:
// 先移除旧的旋转动画 self.spinnerImageView.layer.removeAnimation(forKey: self.spinnerAnimationKey) // 创建缩放动画 let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") scaleAnimation.toValue = 0.0 scaleAnimation.duration = 0.4 scaleAnimation.isRemovedOnCompletion = false scaleAnimation.fillMode = .forwards // 创建旋转动画 let spinAnimation = CABasicAnimation(keyPath: "transform.rotation.z") spinAnimation.toValue = .pi * 2.0 spinAnimation.duration = 1.4 spinAnimation.repeatCount = Float.greatestFiniteMagnitude spinAnimation.isCumulative = true spinAnimation.isRemovedOnCompletion = false // 组合动画组 let animationGroup = CAAnimationGroup() animationGroup.animations = [scaleAnimation, spinAnimation] animationGroup.duration = 0.4 animationGroup.timingFunction = CAMediaTimingFunction(name: .linear) animationGroup.isRemovedOnCompletion = false animationGroup.fillMode = .forwards self.spinnerImageView.layer.add(animationGroup, forKey: "scaleAndSpin")
这样就能同时完成缩放和旋转的过渡,动画结束后也能保持缩放后的状态。
内容的提问来源于stack exchange,提问作者Alan
相关产品推荐
相关产品推荐

