如何为约束更改设置动画?

本文翻译自:How do I animate constraint changes?

I'm updating an old app with an AdBannerView and when there is no ad, it slides off screen. 我正在使用AdBannerView更新一个旧应用,当没有广告时,它会滑出屏幕。 When there is an ad it slides on screen. 出现广告时,它会在屏幕上滑动。 Basic stuff. 基本的东西。

Old style, I set the frame in an animation block. 旧样式,我将帧设置在动画块中。 New style, I have a IBOutlet to the auto-layout constraint which determines the Y position, in this case it's distance from the bottom of the superview, and modify the constant: 新样式,我对自动布局约束有一个IBOutlet ,它确定Y位置,在这种情况下,它是距父视图底部的距离,并修改常量:

- (void)moveBannerOffScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = -32;
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = 0;
    }];
    bannerIsVisible = TRUE;
}

And the banner moves, exactly as expected, but no animation. 横幅完全按预期移动,但没有动画。

UPDATE: I re-watched WWDC 12 talk Best Practices for Mastering Auto Layout which covers animation. 更新:我重新观看了WWDC 12的“精通自动布局的最佳实践”,其中涵盖了动画。 It discusses how to update constraints using CoreAnimation : 它讨论了如何使用CoreAnimation更新约束:

I've tried with the following code, but get the exact same results: 我尝试使用以下代码,但得到的结果完全相同:

- (void)moveBannerOffScreen {
    _addBannerDistanceFromBottomConstraint.constant = -32;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    _addBannerDistanceFromBottomConstraint.constant = 0;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = TRUE;
}

On a side note, I have checked numerous times and this is being executed on the main thread. 附带一提,我已经检查了很多次,并且这是在线程上执行的。


#1楼

参考:https://stackoom.com/question/qxfU/如何为约束更改设置动画


#2楼

Two important notes: 两个重要注意事项:

  1. You need to call layoutIfNeeded within the animation block. 您需要在动画块内调用layoutIfNeeded Apple actually recommends you call it once before the animation block to ensure that all pending layout operations have been completed 苹果实际上建议您在动画块之前调用一次,以确保所有未完成的布局操作已完成

  2. You need to call it specifically on the parent view (eg self.view ), not the child view that has the constraints attached to it. 您需要专门在父视图 (例如self.view )上调用它,而不是在附加了约束的子视图上调用它。 Doing so will update all constrained views, including animating other views that might be constrained to the view that you changed the constraint of (eg View B is attached to the bottom of View A and you just changed View A's top offset and you want View B to animate with it) 这样做将更新所有受约束的视图,包括为其他可能受约束的视图设置动画(例如,将视图B附加到视图A的底部,而您刚刚更改了视图A的顶部偏移,并且希望视图B)制作动画)

Try this: 尝试这个:

Objective-C 目标C

- (void)moveBannerOffScreen {
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = -32;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen { 
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = 0;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = TRUE;
}

Swift 3 迅捷3

UIView.animate(withDuration: 5) {
    self._addBannerDistanceFromBottomConstraint.constant = 0
    self.view.layoutIfNeeded()
}

#3楼

There is an article talk about this: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was 有一篇文章对此进行了讨论: http : //weblog.sivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

In which, he coded like this: 在其中,他这样编码:

- (void)handleTapFrom:(UIGestureRecognizer *)gesture {
    if (_isVisible) {
        _isVisible = NO;
        self.topConstraint.constant = -44.;    // 1
        [self.navbar setNeedsUpdateConstraints];  // 2
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded]; // 3
        }];
    } else {
        _isVisible = YES;
        self.topConstraint.constant = 0.;
        [self.navbar setNeedsUpdateConstraints];
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded];
        }];
    }
}

Hope it helps. 希望能帮助到你。


#4楼

// Step 1, update your constraint
self.myOutletToConstraint.constant = 50; // New height (for example)

// Step 2, trigger animation
[UIView animateWithDuration:2.0 animations:^{

    // Step 3, call layoutIfNeeded on your animated view's parent
    [self.view layoutIfNeeded];
}];

#5楼

I appreciate the answer provided, but I think it would be nice to take it a bit further. 我感谢提供的答案,但我认为将其进一步扩展会很好。

The basic block animation from the documentation 文档中的基本块动画

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

but really this is a very simplistic scenario. 但这确实是一个非常简单的场景。 What if I want to animate subview constraints via the updateConstraints method? 如果要通过updateConstraints方法为子视图约束设置动画怎么办?

An animation block that calls the subviews updateConstraints method 调用子视图updateConstraints方法的动画块

[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
    [self.view layoutIfNeeded];
} completion:nil];

The updateConstraints method is overridden in the UIView subclass and must call super at the end of the method. updateConstraints方法在UIView子类中被重写,并且必须在方法末尾调用super。

- (void)updateConstraints
{
    // Update some constraints

    [super updateConstraints];
}

The AutoLayout Guide leaves much to be desired but it is worth reading. 《自动版式指南》有很多不足之处,但值得阅读。 I myself am using this as part of a UISwitch that toggles a subview with a pair of UITextField s with a simple and subtle collapse animation (0.2 seconds long). 我本人将其用作UISwitch一部分,该UISwitch用一对UITextField和一个简单而细微的折叠动画(长0.2秒)来切换子视图。 The constraints for the subview are being handled in the UIView subclasses updateConstraints methods as described above. 如上所述,子视图的约束在UIView子类的updateConstraints方法中进行处理。


#6楼

I was trying to animate Constraints and was not really easy to found a good explanation. 我试图为约束创建动画,要找到一个好的解释并不容易。

What other answers are saying is totally true: you need to call [self.view layoutIfNeeded]; 其他答案在说的是完全正确的:您需要调用[self.view layoutIfNeeded]; inside animateWithDuration: animations: . animateWithDuration: animations:内部animateWithDuration: animations: However, the other important point is to have pointers for every NSLayoutConstraint you want to animate. 但是,另一个要点是要为每个要设置动画的NSLayoutConstraint设置指针。

I created an example in GitHub . 我在GitHub中创建了一个示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值