我正在更新一个带有AdBannerView的旧应用程序,当没有广告时,它就会滑出屏幕。当有广告时,它就会在屏幕上滑动。基本的东西。
旧的风格,我设置帧在一个动画块。
新样式,我有一个IBOutlet到自动布局约束,它决定了Y的位置,在这种情况下,它是从父视图底部的距离,并修改常数:
- (void)moveBannerOffScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = -32;
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
[UIView animateWithDuration:5 animations:^{
_addBannerDistanceFromBottomConstraint.constant = 0;
}];
bannerIsVisible = TRUE;
}
横幅的移动和预期的完全一样,但是没有动画。
更新:我重新看了WWDC 12演讲《掌握自动布局的最佳实践》,其中包括动画。它讨论了如何使用CoreAnimation更新约束:
我尝试了下面的代码,但得到完全相同的结果:
- (void)moveBannerOffScreen {
_addBannerDistanceFromBottomConstraint.constant = -32;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = FALSE;
}
- (void)moveBannerOnScreen {
_addBannerDistanceFromBottomConstraint.constant = 0;
[UIView animateWithDuration:2 animations:^{
[self.view setNeedsLayout];
}];
bannerIsVisible = TRUE;
}
另一方面,我已经检查了很多次,这是在主线程上执行的。
Swift 4解决方案
UIView.animate
三个简单的步骤:
改变约束条件,例如:
heightAnchor。常数= 50
告诉包含视图它的布局是脏的,并且自动布局应该重新计算布局:
self.view.setNeedsLayout ()
在动画块中告诉布局重新计算布局,这相当于直接设置帧(在这种情况下,自动布局将设置帧):
UIView。animate(withDuration: 0.5) {
self.view.layoutIfNeeded ()
}
最简单的例子:
heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
旁注
有一个可选的第0步-在改变约束之前,你可能想要调用self.view.layoutIfNeeded()来确保动画的起点来自应用了旧约束的状态(以防有一些其他的约束变化不应该包含在动画中):
otherConstraint.constant = 30
// this will make sure that otherConstraint won't be animated but will take effect immediately
self.view.layoutIfNeeded()
heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
UIViewPropertyAnimator
因为在iOS 10中我们获得了一个新的动画机制——UIViewPropertyAnimator,我们应该知道基本上相同的机制适用于它。步骤基本相同:
heightAnchor.constant = 50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
self.view.layoutIfNeeded()
}
animator.startAnimation()
由于animator是动画的封装,我们可以保持对它的引用,并在以后调用它。然而,由于在动画块中我们只是告诉自动布局重新计算帧,我们必须在调用startAnimation之前改变约束。因此,这样的事情是可能的:
// prepare the animator first and keep a reference to it
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
self.view.layoutIfNeeded()
}
// at some other point in time we change the constraints and call the animator
heightAnchor.constant = 50
self.view.setNeedsLayout()
animator.startAnimation()
改变约束和启动动画器的顺序很重要——如果我们只是改变约束并将动画器留到后面的某个点,下一个重绘周期可以调用自动布局重新计算,而更改将不会被动画化。
另外,请记住单个动画器是不可重用的——一旦运行它,就不能“重新运行”它。所以我想没有什么好的理由继续使用动画器,除非我们用它来控制交互式动画。