我正在更新一个带有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;
}
另一方面,我已经检查了很多次,这是在主线程上执行的。
使用Xcode 8.3.3测试Swift 3的解决方案:
self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
只要记住那个自我。calendarViewHeight是一个引用自customView (CalendarView)的约束。我在self上调用了. layoutifneeded()。view和NOT在self。calendarview上
希望这对你有所帮助。
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()
改变约束和启动动画器的顺序很重要——如果我们只是改变约束并将动画器留到后面的某个点,下一个重绘周期可以调用自动布局重新计算,而更改将不会被动画化。
另外,请记住单个动画器是不可重用的——一旦运行它,就不能“重新运行”它。所以我想没有什么好的理由继续使用动画器,除非我们用它来控制交互式动画。
我很感激你提供的答案,但我认为最好能进一步讨论这个问题。
文档中的基本块动画
[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
// Make all constraint changes here
[containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];
但实际上,这是一个非常简单的场景。如果我想通过updateConstraints方法动画子视图约束?
调用子视图updateConstraints方法的动画块
[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
[self.view layoutIfNeeded];
} completion:nil];
updateConstraints方法在UIView子类中被重写,必须在方法的末尾调用super。
- (void)updateConstraints
{
// Update some constraints
[super updateConstraints];
}
自动布局指南有很多不足之处,但值得一读。我自己使用它作为UISwitch的一部分,它使用一个简单而微妙的折叠动画(0.2秒长)来切换带有一对UITextFields的子视图。子视图的约束被处理在UIView子类updateConstraints方法如上所述。
使用Xcode 8.3.3测试Swift 3的解决方案:
self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0
UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
只要记住那个自我。calendarViewHeight是一个引用自customView (CalendarView)的约束。我在self上调用了. layoutifneeded()。view和NOT在self。calendarview上
希望这对你有所帮助。