通过动画调整 UIView 大小时约束不起作用

Posted

技术标签:

【中文标题】通过动画调整 UIView 大小时约束不起作用【英文标题】:Constraints not working when Resizing UIView via Animation 【发布时间】:2014-02-19 06:01:53 【问题描述】:

我现在面临的很奇怪,我知道在 AutoLayout IB 中添加约束很简单。但是当我调整(ZoomIn 动画)UIView 的大小时,我真的无法弄清楚为什么我的简单约束不起作用。

我定位到 zoomIn 的视图工作正常,但其中的子视图定位不正确。约束似乎不起作用。

在此设置中,黄色框是 UIView,绿色框是 UIImageView。 当我点击黄色框时,它应该放大,如下图所示。

这些是约束:

这应该是 zoomIn 动画的预期结果但是我没有运气,黄色框 zoomIn 但绿色框被放置在其旧位置并且没有改变大小。

我已经将 Yellow Box 的前导、尾随、topSpace 和 bottomSpace 放到了 Green Box 中。 我调整黄色框大小的代码是:

- (void) resizeViewWithZoomInAnimation: (UIView*)view duration:(float)secs option:(UIViewAnimationOptions) option 

//sets the new width and height of deal's view
float newWidth = view.superview.frame.size.width - 20;
float newHeight = view.superview.frame.size.height - 20;

[UIView animateWithDuration:secs delay:0.0 options:option
                 animations: ^

                     switch ([view tag]) 
                         case 1:
                             [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, newWidth, newHeight)];
                             break;
                         case 2:
                             [view setFrame:CGRectMake(CGRectGetMaxX(view.frame),CGRectGetMinY(view.frame), -newWidth , newHeight)];
                             break;
                         case 3:
                             [view setFrame:CGRectMake(CGRectGetMinX(view.frame),CGRectGetMaxY(view.frame), newWidth , -newHeight)];
                             break;
                         case 4:
                             [view setFrame:CGRectMake(CGRectGetMaxX(view.frame),CGRectGetMaxY(view.frame), -newWidth, -newHeight)];
                             break;
                     
                 
                 completion:nil];

这应该是 zoomIn 动画的预期结果:

【问题讨论】:

你怎么知道它不起作用?如果调整 UIImageView 的大小,它不一定会调整 UIImageView 显示的 image 的大小。因此,也许图像视图正在按照您的预期调整大小。一种查找方法:为图像视图提供背景颜色,以便您可以看到它的真实位置,而与它包含的图像无关。 但是,如果 UIImageView 真的没有在调整其父视图的大小时被调整大小,那么是的,你的约束有问题。 我之所以设置绿色背景色是为了测试它是否工作正常。问题是,无论我施加什么限制,它都不起作用。你能提出什么建议吗?谢谢 如果绿色框根本不动,在我看来,您对错误的事物进行了限制(即,没有限制作为其超级视图的黄色框)。在 Interface Builder 中为您的视图提供有用的标签,以便约束清楚地告诉您它们正在连接哪些视图。 哦,还有一件事。确保您的视图层次结构是正确的。绿色和黄色框不应该只是主视图(兄弟)的子视图:确保绿色框在内部黄色框(作为它们的子视图),而不仅仅是在它们前面。 【参考方案1】:

当尝试使用自动布局制作动画时,您应该不要直接更改视图的框架。相反,您应该为约束的变化设置动画。

要访问情节提要中的约束,您只需 create IBOutlets 即可。

[containerView layoutIfNeeded]; // complete pending layout operations (optional)
[UIView animateWithDuration:1.0 animations:^

    // Update constraints
    self.viewConstraint1.constant = NEW_VALUE;
    self.viewConstraint2.constant = NEW_VALUE;

    // Animate the changes
    [containerView layoutIfNeeded]; 
];

请注意,您通常希望在您尝试制作动画的视图的超级视图(或更高)上调用 layoutIfNeeded。

我建议阅读 Apple 的 official guide 中有关自动布局的更多信息。

【讨论】:

将我的代码切换为以这种方式工作,非常适合调整大小,但到目前为止调用 [UIView animateWithDuration:secs delay:0.0 options:option animations: ^ [myView setNeedsLayout]; // 约束中的动画变化 completion:nil];不会产生任何动画。【参考方案2】:

对上述答案的调整,我在 UIViewController 中使用

  [self.view layoutIfNeeded];
  [UIView animateWithDuration:.5
                         animations:^
                             myConstraint.constant = 64;
                             [self.view layoutIfNeeded];
                         
                         completion:^(BOOL finished) 
                             // whatever
                         ];

注意更改:Apple 文档建议使用 layoutIfNeeded,并在动画块之前和内部调用它。这样您就可以确保在开始之前清除动画堆栈。

另外,您要在要制作动画的约束的父视图上调用 layoutIfNeeded,而不是在拥有约束的视图上调用。感谢@nkukushkin 的初步回答。

正确设置约束也很重要。 IB 中的“修复约束”工具不需要以适合动画的方式设置它们。对我来说,我必须通过它们并思考我希望依赖项如何工作,这当然是意料之中的,但对于初学者来说可能并不明显(并导致错误)。

【讨论】:

感谢您明确指出在何处进行 layoutIfNeeded 调用。我有一个类似的问题,调整大小工作正常,但没有动画。这解决了它。【参考方案3】:

当您使用约束时,会生成预约束。当您对位置和大小进行操作时,请在为视图设置动画时移除约束或执行以下操作:

yourView.translatesAutoresizingMaskIntoConstraints = YES;

【讨论】:

以上是关于通过动画调整 UIView 大小时约束不起作用的主要内容,如果未能解决你的问题,请参考以下文章

UILabel 调整大小不起作用

iOS - 导航栏内的动画不起作用

使用固定大小的子视图和自动布局调整 UIView 的大小不起作用

动画后自动布局约束不起作用[重复]

将图像居中的 iOS 约束不起作用

带有约束的 UIViewAnimation 在 Swift 中不起作用