iOS - 使用自动布局实现多个同时动画

3
我希望同时执行两个动画,第一个动画在firstView上立即开始。当第一个动画仍在运行时,第二个动画在稍微延迟后在secondView上开始。secondView的约束与firstView有关。此代码可在iOS 8上完美运行。 firstViewsecondViewview的子视图。
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被调用,第一个动画就会停止,并且只有第二个动画会执行。有什么建议吗?

尝试使用UIViewAnimationOptionLayoutSubviews而不是直接调用layoutIfNeeded。虽然它基本上做的是相同的事情,但也许会有所帮助。 - Micky
@Kim 我已经尝试过了,没有帮助。 - tonymontana
如果您无法使用UIView动画找到解决方案,可以尝试使用UIKit动力学。这里有一个很好的教程:http://www.raywenderlich.com/50197/uikit-dynamics-tutorial - Micky
2个回答

2

回答自己的问题。

最终我采用了两步(三步,取决于您如何计算)解决方案来完成动画。首先添加约束,而不调用layoutIfNeeded。然后更新firtViewsecondView的框架。最后,在最后一个动画的完成块中调用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];
}];

0

两个重要注意事项:

  1. 在动画块内部,您需要调用layoutIfNeeded。实际上,苹果公司建议您在动画块之前调用一次,以确保所有挂起的布局操作都已完成。
  2. 您需要特别在父视图(例如self.view)上调用它,而不是附加有约束条件的子视图。这样做将更新所有受约束的视图,包括动画其他可能被约束到您更改约束的视图的视图(例如,View B附加在View A底部,您刚刚更改了View A的顶部偏移量,并希望View 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) {
}];

这正是我在问题中提供的示例代码所做的。 - tonymontana
请检查我是否改变了添加约束的位置。 - Akshay Sunderwani
它无法用于多个动画。这将导致它们全部立即执行,没有任何延迟。 - tonymontana
我正在以相同的方式使用它,并且它的工作方式也是相同的。对于第二个视图也要遵循相同的方式。你尝试过用这种方式吗?@mrvincenzo - Akshay Sunderwani

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接