使用自动布局约束的UIView动画更改

27

假设我有一个项目,看起来像这样:

enter image description here

有两个UIView - 一个名为yellowBox ,另一个名为redBox 。 自动布局约束规定yellowBox 距离超级视图顶部60个点,左右各350个点的空白(即在视图左侧和右侧)。 redBox 具有相同的前导和后续空间约束。 两个框之间有0的垂直空间约束,表示yellowBox 的底部始终直接位于redBox 上方。

当用户点击“展开黄盒子”按钮时,我希望yellowBox的高度增加,并因此使redBox向下移动,以继续满足垂直空间约束(即yellowBox始终在redBox上面)。 这是动画代码:

- (IBAction)expandYellowBox:(id)sender {

    [UIView animateWithDuration:0.5
                     animations:^{
                         CGRect newFrame = self.yellowBox.frame;
                         newFrame.size.height += 50;
                         self.yellowBox.frame = newFrame;
                     }];

}

然而,我一直无法正确地让它工作。正如你所看到的红色图标一样,目前约束存在问题:

enter image description here

这很公平,因为自动布局无法知道框的高度。然而,我不知道如何以这样的方式解决此问题,以使箱子可以调整大小和移动。例如,如果我在yellowBox上指定高度约束,则会防止其被调整大小。如果我将高度约束设置为大于或等于(允许yellowBox高度增加),那么我会得到不同的约束错误:

enter image description here

所有约束都是在Storyboard中使用Xcode建立的 - 没有在代码中编写任何内容。

非常感谢任何帮助。


编辑:事实证明,在单击按钮时yellowBox正在增长 - 只是因为它出现在redBox后面,我没能发现。只有在点击了四次后,它才开始从redBox底部出现。然而,相同的问题仍然存在 - 如何使redBox始终保持在yellowBox底部。


你能检查一下在你的视图控制器中是否调用了viewDidLayoutSubviews方法吗?当执行点击事件时。 - CoolMonster
不,viewDidLayoutSubViews方法没有被调用。 - Skoota
尝试设置边界而不是框架可能有时会起作用。即使在您的代码中重复两次self.yellowBox.frame = newFrame; 有时也可以修复问题。 - CoolMonster
那似乎不起作用,而且多次重复代码(直到它运行)似乎不是解决问题的最佳方案... - Skoota
请检查我的答案和演示。这将有所帮助。 - CoolMonster
3个回答

83

按照shwet-solanki的说法尝试,但在更改约束后,请添加以下行:

[self.view layoutIfNeeded];

IBAction的样子应该是这样的:

- (IBAction)expandYellowBox:(id)sender {

[UIView animateWithDuration:0.5
                 animations:^{
                     self.yellowBoxHeightConstraint.constant += 50;
                     [self.view layoutIfNeeded];
                 }];
}

这里的yellowBoxHeightConstraintyellowBox高度约束的IBOutlet

希望这能有所帮助。


谢谢您的建议,但这正是我试图避免的方法。我不想手动调整redBox的框架,因为它应该通过约束自动移动。在这种情况下,这很简单,但是这个问题中的示例只是一个测试项目,用于演示问题 - 实际问题发生在一个更大的项目中,在那里使用您建议的方法将不可行或难以维护。 - Skoota
希望你已经注意到我编辑了我的回答。当前的方法应该可以工作。请试一下。 - GoGreen
2
你帮我成功通过了面试,谢谢! - vinay chorpa
2
要小心使用layoutIfNeeded,因为它会立即执行布局,这可能会在某些情况下引起不良影响(例如当您从scrollView:didScroll中使用它来将动画绑定到视图的滚动时,这会触发大量事件)。 它也非常苛刻。 在这些情况下,最好使用setNeedsLayout,它会在UI线程有时间时进行布局。 - ncerezo
感谢 @ncerezo 的指点。我在实际项目中也遇到过类似的情况,确实建议使用 setNeedsLayout - GoGreen
显示剩余2条评论

4
  1. 给这两个视图都添加高度约束
  2. 为黄色框的高度约束创建一个IBOutlet
  3. 现在,不要在按钮按下事件中更改黄色框的高度,而是更改高度约束的值。例如,假设您的IBOutlet约束名称是yellowBoxHeightConstraint,则 yellowBoxHeightConstraint.constant += 50;

希望这对您有帮助。


2
谢谢,它确实扩展了yellowBoxredBox固定在yellowBox底部),但它没有执行动画效果 - 它会突然发生。 - Skoota

1
//
//  WPViewController.h
//  AutoLayoutTEst
//
//  Created by VASANTH K on 09/01/14.
//  
//

#import <UIKit/UIKit.h>

@interface WPViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIButton *button1;
- (IBAction)buttClicked:(id)sender;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *heightConstrain;

@property (strong, nonatomic) IBOutlet UIButton *button2;
@end

点击事件
- (IBAction)buttClicked:(id)sender {


    self.heightConstrain.constant=100;


}

在这里,您需要设置黄色按钮的heightConstrain,然后为该按钮创建引用插座,然后更新heightConstrain以更新该按钮的大小,它将自动将您的红色按钮向下移动。

https://github.com/vasanth3008/AutoLayoutHeighDemo

参考我的示例演示项目。

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