我试图动画一些观点,使他们被巨大的键盘挡在景观。它工作得很好,如果我只是简单地动画帧,但其他人认为这是反效果的,我应该更新NSLayoutConstraints代替。然而,它们似乎没有动画效果。有人让他们成功工作了吗?

//heightFromTop is an NSLayoutConstraint referenced from IB
[UIView animateWithDuration:0.25 animations:^{
    self.heightFromTop.constant= 550.f;
}];

结果就是瞬间跳到了刚才提到的高度。


当前回答

我也有类似的问题,这条线索是一个很大的帮助,让它过去。

erurainon的答案让我找到了正确的方向,但我想提出一个稍微不同的答案。来自erurainon的建议代码并不适合我,因为我仍然有一个跳跃而不是一个动画过渡。由cnotethegr8提供的链接给了我工作的答案:

自动布局指南 https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html(一直到页面底部)。

与erurainon的答案有几点不同:

在调用动画方法之前调用容器视图上的layoutIfNeeded(而不是myView上的setNeedsUpdateConstraints)。 在动画块中设置新的约束。 在animations方法的容器视图上调用layoutIfNeeded(在设置约束之后),而不是在myView上。

这将遵循苹果在上面链接中建议的模式。

一个例子

我想要动画一个特定的视图,在点击按钮时关闭或展开它。由于我使用自动布局,并不想硬编码任何尺寸(在我的情况下高度)在代码中,我决定在viewDidLayoutSubviews中捕获高度。当使用自动布局时,你需要使用这个方法而不是viewWillAppear。由于viewDidLayoutSubviews可能会被调用很多次,我使用BOOL来让我知道我的初始化的第一次执行。

// Code snippets

@property (weak, nonatomic) IBOutlet UIView *topView; // Container for minimalView
@property (weak, nonatomic) IBOutlet UIView *minimalView; // View to animate

@property (nonatomic) CGFloat minimalViewFullHeight; // Original height of minimalView

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *minimalViewHeightConstraint;

@property (nonatomic) BOOL executedViewDidLayoutSubviews;


- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];


    // First execution of viewDidLayoutSubviews?
    if(!self.executedViewDidLayoutSubviews){
        self.executedViewDidLayoutSubviews = YES;


        // Record some original dimensions
        self.minimalViewFullHeight = self.minimalView.bounds.size.height;


        // Setup our initial view configuration & let system know that 
        // constraints need to be updated.
        self.minimalViewHeightConstraint.constant = 0.0;
        [self.minimalView setNeedsUpdateConstraints];

        [self.topView layoutIfNeeded];
    }
}

调整整个动作片段的大小

// An action to close our minimal view and show our normal (full) view
- (IBAction)resizeFullAction:(UIButton *)sender {

    [self.topView layoutIfNeeded];

    [UIView transitionWithView:self.minimalView
                  duration:1.0
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    self.minimalViewHeightConstraint.constant = 0.0;

                    // Following call to setNeedsUpdateConstraints may not be necessary
                    [self.minimalView setNeedsUpdateConstraints];

                    [self.topView layoutIfNeeded];

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

    // Other code to show full view
    // ...
}

调整小动作片段的大小

// An action to open our minimal view and hide our normal (full) view
- (IBAction)resizeSmallAction:(UIButton *)sender {

    [self.topView layoutIfNeeded];

    [UIView transitionWithView:self.minimalView
                  duration:1.0
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    self.minimalViewHeightConstraint.constant = self.minimalViewFullHeight;
                    [self.minimalView setNeedsUpdateConstraints];

                    [self.topView layoutIfNeeded];

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

        // Other code to hide full view
        // ...
    }

如果你愿意,你可以使用animateWithDuration代替transitionWithView。

希望这能有所帮助。

其他回答

我尝试了@百夫长的方法,但不知怎的,我的视图会动画到一个错误的帧,如果它是从故事板加载。如果我用updateConstraintsIfNeeded替换第一个layoutIfNeeded,问题就消失了,尽管我不知道为什么。如果有人能解释一下,我将不胜感激。

[self.view updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0 animations:^{
    self.myConstraint.constant= 100;
    [self.view layoutIfNeeded];
}];

我也有类似的问题,这条线索是一个很大的帮助,让它过去。

erurainon的答案让我找到了正确的方向,但我想提出一个稍微不同的答案。来自erurainon的建议代码并不适合我,因为我仍然有一个跳跃而不是一个动画过渡。由cnotethegr8提供的链接给了我工作的答案:

自动布局指南 https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html(一直到页面底部)。

与erurainon的答案有几点不同:

在调用动画方法之前调用容器视图上的layoutIfNeeded(而不是myView上的setNeedsUpdateConstraints)。 在动画块中设置新的约束。 在animations方法的容器视图上调用layoutIfNeeded(在设置约束之后),而不是在myView上。

这将遵循苹果在上面链接中建议的模式。

一个例子

我想要动画一个特定的视图,在点击按钮时关闭或展开它。由于我使用自动布局,并不想硬编码任何尺寸(在我的情况下高度)在代码中,我决定在viewDidLayoutSubviews中捕获高度。当使用自动布局时,你需要使用这个方法而不是viewWillAppear。由于viewDidLayoutSubviews可能会被调用很多次,我使用BOOL来让我知道我的初始化的第一次执行。

// Code snippets

@property (weak, nonatomic) IBOutlet UIView *topView; // Container for minimalView
@property (weak, nonatomic) IBOutlet UIView *minimalView; // View to animate

@property (nonatomic) CGFloat minimalViewFullHeight; // Original height of minimalView

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *minimalViewHeightConstraint;

@property (nonatomic) BOOL executedViewDidLayoutSubviews;


- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];


    // First execution of viewDidLayoutSubviews?
    if(!self.executedViewDidLayoutSubviews){
        self.executedViewDidLayoutSubviews = YES;


        // Record some original dimensions
        self.minimalViewFullHeight = self.minimalView.bounds.size.height;


        // Setup our initial view configuration & let system know that 
        // constraints need to be updated.
        self.minimalViewHeightConstraint.constant = 0.0;
        [self.minimalView setNeedsUpdateConstraints];

        [self.topView layoutIfNeeded];
    }
}

调整整个动作片段的大小

// An action to close our minimal view and show our normal (full) view
- (IBAction)resizeFullAction:(UIButton *)sender {

    [self.topView layoutIfNeeded];

    [UIView transitionWithView:self.minimalView
                  duration:1.0
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    self.minimalViewHeightConstraint.constant = 0.0;

                    // Following call to setNeedsUpdateConstraints may not be necessary
                    [self.minimalView setNeedsUpdateConstraints];

                    [self.topView layoutIfNeeded];

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

    // Other code to show full view
    // ...
}

调整小动作片段的大小

// An action to open our minimal view and hide our normal (full) view
- (IBAction)resizeSmallAction:(UIButton *)sender {

    [self.topView layoutIfNeeded];

    [UIView transitionWithView:self.minimalView
                  duration:1.0
                   options:UIViewAnimationOptionTransitionCrossDissolve
                animations:^{
                    self.minimalViewHeightConstraint.constant = self.minimalViewFullHeight;
                    [self.minimalView setNeedsUpdateConstraints];

                    [self.topView layoutIfNeeded];

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

        // Other code to hide full view
        // ...
    }

如果你愿意,你可以使用animateWithDuration代替transitionWithView。

希望这能有所帮助。

只要遵循这个模式:

self.heightFromTop.constant = 550.0f;
[myView setNeedsUpdateConstraints];

[UIView animateWithDuration:0.25f animations:^{
   [myView layoutIfNeeded];
}];

myView是self所在的视图。heightFromTop被添加到。你的视图正在“跳跃”,因为你在动画块中所做的唯一一件事是设置约束,这不会立即引起布局。在代码中,布局发生在设置heightFromTop后的下一次运行循环中。常量,到那时你已经超出了动画块的范围。

在Swift 2中:

self.heightFromTop.constant = 550
myView.setNeedsUpdateConstraints()

UIView.animateWithDuration(0.25, animations: {
   myView.layoutIfNeeded()
})

The Apple's suggested way is a little bit different (See example in "Animating Changes Made by Auto Layout" section). First you need to call layoutIfNeeded before the animation. Then add your animation stuff inside the animation block and then call layoutIfNeeded at the end again. For the guys like me who are transitioning to autolayout, its more similar way to previous animations that we were doing with the frames inside animation blocks. We just need to call layoutIfNeeded twice - before animations and after animations:

[self.view layoutIfNeeded]; // Ensures that all pending layout operations have been completed

[UIView animateWithDuration:1.0f animations:^{

  // Make all constraint changes here
  self.heightFromTop.constant= 550.f;

  [self.view layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes

}];