自动布局,约束和动画

时间:2013-11-11 05:17:23

标签: ios objective-c autolayout

我们假设我有UIView

enter image description here

有这些相对约束:

@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时,该按钮应该移动到视图的右下角。我们可以轻松地使用两个约束来定义按钮和底部布局指南之间的底部空间以及从按钮和视图右边缘的右空间(尾随空间)。

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

动画场景的简单和常见情况,但它给我带来了一些问题。想法?

修改

当用户点击UIButton时,我需要按钮:

  1. 将其标题更改为“Second”
  2. 等待1秒钟并移至右下角(删除顶部和左侧边距约束并添加底部和右边距约束)
  3. 将其标题更改为“第三”
  4. 等待1秒钟并移至右上角(移除下边距约束 并添加上边距约束)
  5. 我是否真的必须使用这个凌乱的代码?

    @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

3 个答案:

答案 0 :(得分:11)

删除左侧和顶部约束,添加底部和右侧约束,然后在动画块中调用layoutIfNeeded以设置新位置的动画。第二种方法中的代码,move2可以嵌入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];
}

答案 1 :(得分:1)

对于动画,您需要更改左侧和上侧约束的常量,而不是添加新约束。如下:

 self.mBtnTopConstraint.constant = yourval1;
    self.mBtmLeftConstraint.constant = yourval2;
    [yourbtn setNeedsUpdateConstraints];

    [UIView animateWithDuration:0.5 animations:^{

            [yourbtn layoutIfNeeded];

        } completion:^(BOOL isFinished){
        }];

希望这有帮助。

答案 2 :(得分:-1)

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

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

如果使用cocoapod" SBP"用几行就可以做到这一点。 Here's a tutorial