我正在尝试动画一些视图,以便它们被景观中的巨型键盘阻挡。如果我简单地为框架设置动画,它的效果很好,但是其他人认为这会适得其反,我应该更新NSLayoutConstraints。但是,它们似乎不具有动画效果。有没有人让他们成功地工作?
//heightFromTop is an NSLayoutConstraint referenced from IB
[UIView animateWithDuration:0.25 animations:^{
self.heightFromTop.constant= 550.f;
}];
结果是立即跳到有问题的高度。
答案 0 :(得分:467)
请遵循以下确切模式:
self.heightFromTop.constant = 550.0f;
[myView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.25f animations:^{
[myView layoutIfNeeded];
}];
其中myView
是添加self.heightFromTop
的视图。你的观点是"跳跃"因为你在动画块中唯一做的就是设置约束,这不会立即引起布局。在您的代码中,布局在您设置heightFromTop.constant
之后在下一个运行循环中发生,到那时您已经超出了动画块的范围。
在Swift 2中:
self.heightFromTop.constant = 550
myView.setNeedsUpdateConstraints()
UIView.animateWithDuration(0.25, animations: {
myView.layoutIfNeeded()
})
答案 1 :(得分:79)
Apple建议的方式略有不同(See example in "Animating Changes Made by Auto Layout" section)。首先,您需要在动画之前调用layoutIfNeeded。然后在动画块中添加动画内容,然后再次调用layoutIfNeeded。对于像我这样过渡到自动布局的人来说,它与我们在动画块中的帧所做的以前的动画更相似。我们只需要调用layoutIfNeeded两次 - 在动画之前和动画之后:
[self.view layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0f animations:^{
// Make all constraint changes here
self.heightFromTop.constant= 550.f;
[self.view layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];
答案 2 :(得分:10)
我尝试了@ Centurion的方法,但不知何故,如果从故事板加载,我的视图会动画到错误的帧。如果我用layoutIfNeeded
替换第一个updateConstraintsIfNeeded
,问题就会消失,尽管我不知道为什么。如果有人能给出解释,那将非常感激。
[self.view updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0 animations:^{
self.myConstraint.constant= 100;
[self.view layoutIfNeeded];
}];
答案 3 :(得分:4)
我遇到了类似的问题,这个帖子对于克服这个问题非常有帮助。
来自erurainon的回答让我走上正轨,但我想提出一个稍微不同的答案。来自erurainon的建议代码对我来说不起作用,因为我仍然有一个跳跃而不是动画过渡。 cnotethegr8提供的链接给了我工作答案:
自动布局指南 https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html(一直到页面底部)。
与erurainon的回答有些不同:
这将遵循Apple在上面链接中建议的模式。
示例
我想为特定视图设置动画,只需点击一下按钮即可关闭或展开它。由于我使用autolayout并且不想在代码中硬编码任何维度(在我的情况下是高度),我决定在viewDidLayoutSubviews中捕获高度。使用autolayout时,您需要使用此方法而不是viewWillAppear。由于可以多次调用viewDidLayoutSubviews,因此我使用BOOL告诉我初始化的第一次执行。
// Code snippets
@property (weak, nonatomic) IBOutlet UIView *topView; // Container for minimalView
@property (weak, nonatomic) IBOutlet UIView *minimalView; // View to animate
@property (nonatomic) CGFloat minimalViewFullHeight; // Original height of minimalView
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *minimalViewHeightConstraint;
@property (nonatomic) BOOL executedViewDidLayoutSubviews;
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
// First execution of viewDidLayoutSubviews?
if(!self.executedViewDidLayoutSubviews){
self.executedViewDidLayoutSubviews = YES;
// Record some original dimensions
self.minimalViewFullHeight = self.minimalView.bounds.size.height;
// Setup our initial view configuration & let system know that
// constraints need to be updated.
self.minimalViewHeightConstraint.constant = 0.0;
[self.minimalView setNeedsUpdateConstraints];
[self.topView layoutIfNeeded];
}
}
调整完整操作代码段
// An action to close our minimal view and show our normal (full) view
- (IBAction)resizeFullAction:(UIButton *)sender {
[self.topView layoutIfNeeded];
[UIView transitionWithView:self.minimalView
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.minimalViewHeightConstraint.constant = 0.0;
// Following call to setNeedsUpdateConstraints may not be necessary
[self.minimalView setNeedsUpdateConstraints];
[self.topView layoutIfNeeded];
} completion:^(BOOL finished) {
;
}];
// Other code to show full view
// ...
}
调整小型操作代码段
// An action to open our minimal view and hide our normal (full) view
- (IBAction)resizeSmallAction:(UIButton *)sender {
[self.topView layoutIfNeeded];
[UIView transitionWithView:self.minimalView
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.minimalViewHeightConstraint.constant = self.minimalViewFullHeight;
[self.minimalView setNeedsUpdateConstraints];
[self.topView layoutIfNeeded];
} completion:^(BOOL finished) {
;
}];
// Other code to hide full view
// ...
}
如果愿意,可以使用animateWithDuration而不是transitionWithView。
希望这有帮助。