AutoLayout,约束和animation

假设我有这个UIView

在这里输入图像说明

与这些相对的限制:

 @property (strong, nonatomic) IBOutlet NSLayoutConstraint *leftMarginConstraint; @property (strong, nonatomic) IBOutlet NSLayoutConstraint *topMarginConstraint; @property (strong, nonatomic) IBOutlet NSLayoutConstraint *widthConstraint; @property (strong, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint; 

好,现在让我们假设当用户点击那个UIButton ,button应该移动到视图的右下angular。 我们可以很容易地使用两个约束来定义button和底部布局指南之间的底部空间,以及从button和视图右边缘的右边空间(尾部空间)。

问题是UIButton已经有两个约束(left / top)和两个约束来定义它的宽度和高度,所以我们不能添加两个新约束,因为它们会与其他约束冲突。

一个animation场景的简单而普遍的情况,但是却造成了一些问题。 想法?

编辑

当用户点击UIButton ,我需要button:

  1. 将其标题更改为“第二”
  2. 等待1秒,然后移动到右下angular(移除顶部和左侧边距约束,并添加底部和右侧边距约束)
  3. 将其标题更改为“第三”
  4. 等待1秒,然后移到右上angular(移除底部边距约束并添加顶部边距约束)

我真的很想使用这个混乱的代码吗?

 @implementation ViewController { NSLayoutConstraint *_topMarginConstraint; NSLayoutConstraint *_leftMarginConstraint; NSLayoutConstraint *_bottomMarginConstraint; NSLayoutConstraint *_rightMarginConstraint; } - (IBAction)buttonPressed:(id)sender { UIButton *button = sender; // 1. [sender setTitle:@"Second" forState:UIControlStateNormal]; // 2. double delayInSeconds = 1.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { [button removeConstraints:@[self.leftMarginConstraint, self.topMarginConstraint]]; _bottomMarginConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:0 toItem:button attribute:NSLayoutAttributeBottom multiplier:1 constant:20]; [self.view addConstraint:_bottomMarginConstraint]; _rightMarginConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeRight relatedBy:0 toItem:button attribute:NSLayoutAttributeRight multiplier:1 constant:20]; [self.view addConstraint:_rightMarginConstraint]; [UIView animateWithDuration:1 animations:^{ [self.view layoutIfNeeded]; } completion:^(BOOL finished) { // 3. [sender setTitle:@"Third" forState:UIControlStateNormal]; // 4. double delayInSeconds = 1.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { [button removeConstraint:_bottomMarginConstraint]; _topMarginConstraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTop relatedBy:0 toItem:button attribute:NSLayoutAttributeTop multiplier:1 constant:20]; [UIView animateWithDuration:1 animations:^{ [self.view layoutIfNeeded]; }]; }); }]; }); } 

严重? :d

删除左边和上边的约束,添加底部和右边的约束,然后调用animation块中的layoutIfNeededanimation到新的位置。 第二个方法中的代码move2可以embedded到move1的完成块中,但是如果在两个单独的方法中保持这两个方法(它需要添加另一个属性bottomCon),我发现它更容易阅读:

 - (IBAction)move1:(UIButton *)sender { [sender setTitle:@"Second" forState:UIControlStateNormal]; [sender layoutIfNeeded]; [self.view removeConstraints:@[self.leftCon,self.topCon]]; self.bottomCon = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeBottom relatedBy:0 toItem:self.button attribute:NSLayoutAttributeBottom multiplier:1 constant:20]; [self.view addConstraint:self.bottomCon]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeRight relatedBy:0 toItem:self.button attribute:NSLayoutAttributeRight multiplier:1 constant:20]]; [UIView animateWithDuration:1 delay:1.0 options:0 animations:^{ [self.view layoutIfNeeded]; } completion:^(BOOL finished) { [sender setTitle:@"Third" forState:UIControlStateNormal]; [self move2]; }]; } -(void)move2 { [self.view removeConstraint:self.bottomCon]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.button attribute:NSLayoutAttributeTop multiplier:1 constant:-20]]; [UIView animateWithDuration:1 delay:1.0 options:0 animations:^{ [self.view layoutIfNeeded]; } completion:nil]; } 

对于animation,你需要改变左边和上边的约束的常量,而不是增加新的约束。 如下:

  self.mBtnTopConstraint.constant = yourval1; self.mBtmLeftConstraint.constant = yourval2; [yourbtn setNeedsUpdateConstraints]; [UIView animateWithDuration:0.5 animations:^{ [yourbtn layoutIfNeeded]; } completion:^(BOOL isFinished){ }]; 

希望这可以帮助。

您可以使用所需的结束约束来创build占位符UIView,并使用占位符UIView约束来交换原始约束。

这样它就保持了故事板的布局约束,并防止你的代码混乱。 它还为您提供了在xcode的预览部分查看animation效果的附加效果。

如果使用cocoapod“SBP”来做到这一点,只需几行。 这是一个教程 。