在viewDidLayoutSubviews中更改框架

时间:2014-11-24 17:08:51

标签: ios objective-c uiview uiviewcontroller

当首次显示视图控制器的视图时,我想运行一个动画,其中视图控制器中的所有元素都从屏幕底部外部滑动到它们的自然位置。为实现这一目标,我在subview.frame.origin.y += self.view.frame.size.heightviewDidLayoutSubviews。我也试过viewWillAppear,但它根本不起作用。然后,我使用subview.frame.origin.y -= self.view.frame.size.height中的viewDidAppear将它们设置为自然位置。

问题是在整个视图控制器的整个生命周期中多次调用viewDidLayoutSubviews。因此,当显示键盘的事情发生时,我的所有内容都会在视图外被替换。

有没有更好的方法呢?我是否需要添加某种标志来检查动画是否已经运行?

编辑:这是代码。我在prepareAppearance中呼叫viewDidLayoutSubviews,这有效,但viewDidLayoutSubviews在整个控制器的生命周期内被多次调用。

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self prepareAppearance];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self animateAppearance];
}


- (NSArray *)animatableViews
{
    return @[self.createAccountButton, self.facebookButton, self.linkedInButton, self.loginButton];
}

- (void)prepareAppearance
{
    NSArray * views = [self animatableViews];
    NSUInteger count = [views count];

    for (NSUInteger it=0 ; it < count ; ++it) {

        UIView * view = [views objectAtIndex:it];
        CGRect frame = view.frame;

        // Move the views outside the screen, to the bottom
        frame.origin.y += self.view.frame.size.height;

        [view setFrame:frame];
    }
}

- (void)animateAppearance
{
    NSArray * views = [self animatableViews];
    NSUInteger count = [views count];

    for (NSUInteger it=0 ; it < count ; ++it) {

        __weak UIView * weakView = [views objectAtIndex:it];
        CGRect referenceFrame = self.view.frame;

        [UIView animateWithDuration:0.4f
                              delay:0.05f * it
                            options:UIViewAnimationOptionCurveEaseOut
                         animations:^{

                             CGRect frame = weakView.frame;
                             frame.origin.y -= referenceFrame.size.height;

                             [weakView setFrame:frame];
                         }
                         completion:^(BOOL finished) {
                         }];
    }
}

2 个答案:

答案 0 :(得分:7)

如果您需要在显示视图时制作动画,然后不再触摸子视图,我建议如下:

  • 不要改变/触摸viewDidLayoutSubviews
  • viewWillAppear
  • 中添加逻辑以将元素移动到屏幕外(到动画之前的初始位置
  • 添加逻辑以将元素设置为viewDidAppear
  • 中的正确位置

<强>更新

如果你正在使用自动布局(这是非常好的事情),你可以通过直接更改它们的框架来动画视图(因为自动布局会忽略它并再次更改它们)。您需要做的是将出口暴露给负责Y位置的约束(在您的情况下)并更改约束而不是设置框架。

在更新动画方法中的约束后,也不要忘记包含对[weakView layoutIfNeeded]的调用。

答案 1 :(得分:0)

我在viewDidAppear:做了两件事。似乎在调用viewDidAppear:时,视图实际上不可见,但即将到来。因此,如果在那里替换它们,UI元素永远不会显示在它们的初始位置。