iOS - 使用自动布局执行多个同步动画
iOS - Performing several simultaneous animations with autolayout
我想同时执行两个运动动画。 firstView
上的第一个动画立即开始。 secondView
上的第二个动画在稍有延迟后开始,而第一个动画仍然是 运行。 secondView
约束与 firstView
有关。该代码在 iOS 8 上运行良好。
firstView
和 secondView
是 view
的子视图
view
|--- firstView
|--- secondView
代码:
UIView *firstView = ...;
UIView *secondView = ...;
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:firstView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint];
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.5 delay:0.15 options:UIViewAnimationOptionCurveEaseInOut animations:^{
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:secondView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:firstView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint];
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
在 iOS 7 上,一旦调用第二个 layoutIfNeeded
,第一个动画停止,只有第二个动画动画。
有什么建议吗?
两个重要说明:
- 您需要在动画块中调用layoutIfNeeded。苹果
实际上建议你在动画块之前调用它一次
确保所有挂起的布局操作都已完成。
- 您需要在父视图上专门调用它(例如
self.view), 而不是附加了约束的子视图
它。这样做会更新所有受约束的视图,包括动画
可能受限于您更改的视图的其他视图
的约束(例如,视图 B 附加到视图 A 的底部
并且您刚刚更改了视图 A 的顶部偏移并且您希望视图 B
用它制作动画)。
你必须这样做:
[self.view layoutIfNeeded];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:firstView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint];
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
回答我自己的问题。
我最终用两步(三步,取决于你如何计算)解决方案来制作动画。首先添加约束而不调用layoutIfNeeded
。然后更新 firtView
和 secondView
帧。最后在最后一个动画的完成块中调用layoutIfNeeded
。
代码:
UIView *firstView = ...;
UIView *secondView = ...;
/* first step */
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:firstView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint1];
NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:secondView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:firstView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint2];
/* second step */
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect firstViewFrame = CGRectMake(...); // set frame according to constaint1
firstView.frame = firstViewFrame;
}];
[UIView animateWithDuration:0.5 delay:0.15 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect secondViewFrame = CGRectMake(...); // set frame according to constaint2
secondView.frame = secondViewFrame;
} completion:^(BOOL finished) {
/* second and a half step */
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
我想同时执行两个运动动画。 firstView
上的第一个动画立即开始。 secondView
上的第二个动画在稍有延迟后开始,而第一个动画仍然是 运行。 secondView
约束与 firstView
有关。该代码在 iOS 8 上运行良好。
firstView
和 secondView
是 view
view
|--- firstView
|--- secondView
代码:
UIView *firstView = ...;
UIView *secondView = ...;
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:firstView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint];
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
[UIView animateWithDuration:0.5 delay:0.15 options:UIViewAnimationOptionCurveEaseInOut animations:^{
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:secondView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:firstView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint];
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
在 iOS 7 上,一旦调用第二个 layoutIfNeeded
,第一个动画停止,只有第二个动画动画。
有什么建议吗?
两个重要说明:
- 您需要在动画块中调用layoutIfNeeded。苹果 实际上建议你在动画块之前调用它一次 确保所有挂起的布局操作都已完成。
- 您需要在父视图上专门调用它(例如 self.view), 而不是附加了约束的子视图 它。这样做会更新所有受约束的视图,包括动画 可能受限于您更改的视图的其他视图 的约束(例如,视图 B 附加到视图 A 的底部 并且您刚刚更改了视图 A 的顶部偏移并且您希望视图 B 用它制作动画)。
你必须这样做:
[self.view layoutIfNeeded];
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:firstView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint];
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
}];
回答我自己的问题。
我最终用两步(三步,取决于你如何计算)解决方案来制作动画。首先添加约束而不调用layoutIfNeeded
。然后更新 firtView
和 secondView
帧。最后在最后一个动画的完成块中调用layoutIfNeeded
。
代码:
UIView *firstView = ...;
UIView *secondView = ...;
/* first step */
NSLayoutConstraint *constraint1 = [NSLayoutConstraint constraintWithItem:firstView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLayoutGuide attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint1];
NSLayoutConstraint *constraint2 = [NSLayoutConstraint constraintWithItem:secondView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:firstView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
[self.view addConstraint:constraint2];
/* second step */
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect firstViewFrame = CGRectMake(...); // set frame according to constaint1
firstView.frame = firstViewFrame;
}];
[UIView animateWithDuration:0.5 delay:0.15 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect secondViewFrame = CGRectMake(...); // set frame according to constaint2
secondView.frame = secondViewFrame;
} completion:^(BOOL finished) {
/* second and a half step */
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];