我如何动画约束更改?

我正在使用AdBannerView更新旧应用,当没有广告时,它会滑出屏幕。 有广告时,它会在屏幕上滑动。 基本的东西。

旧样式,我在一个动画块中设置框架。 新的风格,我有一个IBOutlet的约束,它决定了Y的位置,在这种情况下,它是从超级视图底部的距离,并修改常数。

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

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

横幅的移动与预期完全相同,但没有动画。

更新:我重新观看了包含动画的WWDC12视频“掌握自动布局的最佳实践”。 它讨论了如何使用CoreAnimation更新约束。

在这里输入图像描述在这里输入图像描述

我已经尝试了下面的代码,但获得完全相同的结果。

- (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;
}

在附注中,我已经检查了很多次,并且正在主线程上执行。


两个重要提示:

  • 您需要在动画块中调用layoutIfNeeded 。 Apple实际上建议您在动画块之前调用一次,以确保所有挂起的布局操作都已完成

  • 你需要在父视图 (比如self.view )上专门调用它,而不是附加了约束的子视图。 这样做会更新所有受限制的视图,包括动画其他视图,这些视图可能会受限于您更改约束的视图(例如,视图B附加到视图A的底部,并且您刚刚更改视图A的顶部偏移并且您希望视图B用它制作动画)

  • 尝试这个:

    Objective-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;
    }
    

    斯威夫特3

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

    我非常感谢所提供的答案,但我认为这样做会更好一点。

    文档中的基本块动画

    [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
    }];
    

    但真的这是一个非常简单的情况。 如果我想通过updateConstraints方法来动画子视图约束呢?

    调用子视图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];
    

    updateConstraints方法在UIView子类中被覆盖,并且必须在方法结束时调用super。

    - (void)updateConstraints
    {
        // Update some constraints
    
        [super updateConstraints];
    }
    

    AutoLayout指南留下了许多不足之处,但值得一读。 我自己使用这个作为一个UISwitch一部分,它使用一对简单的细微折叠动画(0.2秒长)切换一对UITextField的子视图。 如上所述,子视图的约束正在UIView子类的updateConstraints方法中处理。


    通常,您只需更新约束并在动画块内调用layoutIfNeeded 。 这可以是改变.constant一个的属性NSLayoutConstraint ,加入除去约束(iOS的7),或改变.active约束的属性(的iOS 8和9)。

    示例代码:

    [UIView animateWithDuration:0.3 animations:^{
        // Move to right
        self.leadingConstraint.active = false;
        self.trailingConstraint.active = true;
    
        // Move to bottom
        self.topConstraint.active = false;
        self.bottomConstraint.active = true;
    
        // Make the animation happen
        [self.view setNeedsLayout];
        [self.view layoutIfNeeded];
    }];
    

    样本设置:

    Xcode Project如此示例动画项目。

    争议

    关于约束是应该在动画块之前还是内部进行更改存在一些问题(请参阅前面的答案)。

    以下是教授iOS的Martin Pilkington和编写Auto Layout的Ken Ferry之间的Twitter对话。 Ken解释说,尽管改变动画块之外的常量现在可以工作,但这并不安全,他们应该真的在动画块进行更改。 https://twitter.com/kongtomorrow/status/440627401018466305

    动画:

    示例项目

    以下是一个简单的项目,展示如何将视图变成动画。 它使用Objective C并通过更改多个约束的.active属性来为视图添加动画。 https://github.com/shepting/SampleAutoLayoutAnimation

    链接地址: http://www.djcxy.com/p/25889.html

    上一篇: How do I animate constraint changes?

    下一篇: How to support both iPad and iPhone retina graphics in universal apps