我有一组视图(UIStackView.arrangedSubviews
),我想用UIView.animate()
制作动画。但是我只想在前一个元素完成时开始动画下一个元素。
我想找到一个有点“优雅”的解决方案。我尝试了两种不同的方法,但我对它们都很困惑。我怎样才能做到这一点?
let animate = { (views: [UIView]) -> () in
guard let view = views.first else { return }
UIView.animate(
withDuration: 0.5,
animations: {
view.frame.origin.y -= 30.0
view.alpha = 1.0
},
completion: { finished in
if finished {
// TODO: Only start animating next view when previous is finished?
animate(views.removeFirst()) // ERROR: Variable used within itself
}
})
}
let _ = stackView.arrangedSubviews.map { view -> UIView in
view.frame.origin.y += 30.0
UIView.animate(
withDuration: 0.5,
animations: {
view.frame.origin.y -= 30.0
view.alpha = 1.0
},
completion: { finished in
// TODO: Only start animating next view when previous is finished?
})
return view
}
答案 0 :(得分:3)
如何枚举它们,并使用completion
制作动画,但使用delay
参数?您可以将i
视图的延迟计算为i * animDuration
:
let animDuration = 0.5
for (index, view) in stackView.arrangedSubviews.enumerated() {
view.frame.origin.y += 30.0
UIView.animate(withDuration: animDuration, delay: animDuration * Double(index), options: [.curveLinear], animations: {
view.alpha = 1
view.frame.origin.y -= 30.0
}, completion: nil)
}
P.S。:正如旁注,UIStackView
使用自动布局来布置其排列的子视图。小心直接设置框架。
修改强>
虽然我认为您可以非常确定使用delay
可以按预期工作,但您可以尝试使用UIViewPropertyAnimator
个对象来链接动画:
var animators: [UIViewPropertyAnimator] = []
stackView.arrangedSubviews.forEach({ (view) in
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
view.frame.origin.y += 30.0
animator.addAnimations {
view.alpha = 1
view.frame.origin.y -= 30.0
}
// start this animator in completion of the previous one (if there is previous one)
let previousAnimator = animators.last
previousAnimator?.addCompletion({ (_) in
animator.startAnimation()
})
// append new animator to animators
animators.append(animator)
})
// now you should be able to run the chain by starting the first animator
animators.first?.startAnimation()