[ios] 我如何动画约束更改?


Answers

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

文档中的基本块动画

[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方法中处理。

Question

我正在使用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;
}

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




工作解决方案100% Swift 3.1

我已阅读所有答案,并希望分享我在所有应用程序中使用的代码和层次结构,以便正确地为它们制作动画,此处有些解决方案无法正常工作,此时应在较慢的设备(例如iPhone 5)上检查它们。

self.view.layoutIfNeeded() // Force lays of all subviews on root view
UIView.animate(withDuration: 0.5) { [weak self] in // allowing to ARC to deallocate it properly
       self?.tbConstraint.constant = 158 // my constraint constant change
       self?.view.layoutIfNeeded() // Force lays of all subviews on root view again.
}



使用Xcode 8.3.3工作并测试了Swift 3的解决方案:

self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0

UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)

请记住,self.calendarViewHeight是一个涉及到customView(CalendarView)的约束。 我在self.view上调用了.layoutIfNeeded(),而在self.calendarView上调用了该函数

希望这个帮助。




迅捷解决方案:

yourConstraint.constant = 50
UIView.animateWithDuration(1, animations: yourView.layoutIfNeeded)



有一篇文章谈论这个: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was : http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

其中,他编码如下:

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

希望能帮助到你。




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



Related