在 viewDidLayoutSubviews 中更改框架 [英] Changing a frame in viewDidLayoutSubviews

查看:76
本文介绍了在 viewDidLayoutSubviews 中更改框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

When a view controller's view is first shown I want to run an animation in which all elements in the view controller slide from outside the bottom of the screen to their natural positions. To achieve this, I do subview.frame.origin.y += self.view.frame.size.height in viewDidLayoutSubviews. I also tried viewWillAppear, but it doesn't work at all. Then I animate them up to their natural positions with subview.frame.origin.y -= self.view.frame.size.height in viewDidAppear.

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

The problem is that viewDidLayoutSubviews is called several times throughout the view controller's lifespan. As such, when things like showing the keyboard happen all my content gets replaced outside the view again.

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

Is there a better method for doing this? Do I need to add some sort of flag to check whether the animation has already run?

这是代码.在这里,我在 viewDidLayoutSubviews 中调用 prepareAppearance,这是有效的,但是 viewDidLayoutSubviews 在控制器的整个生命周期中被多次调用.

here's the code. Here I'm calling prepareAppearance in viewDidLayoutSubviews, which works, but viewDidLayoutSubviews is called multiple times throughout the controller's life span.

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

推荐答案

如果您需要在视图出现时设置动画,然后不触摸子视图,我建议如下:

If you need to animate something when view will appear and then not touch subviews later, I would suggest the following:

  • 不要改变/触摸viewDidLayoutSubviews
  • viewWillAppear
  • 中添加将元素移动到屏幕外的逻辑(到它们的初始位置动画之前)
  • 添加逻辑以在 viewDidAppear
  • 中将元素动画到其适当位置
  • Don't change/touch viewDidLayoutSubviews
  • Add logic to move elements outside the screen (to their initial position before animation) in viewWillAppear
  • Add logic to animate elements into their proper position in viewDidAppear

更新:

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

If you're using auto-layout (which is very good thing), you can't animate views by changing their frames directly (because auto-layout would ignore that and change them again). What you need to do is to expose outlets to constraints responsible for Y-position (in your case) and change that constraints rather then setting frames.

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

Also don't forget to include call to [weakView layoutIfNeeded] after you update constraints in the animation method.

这篇关于在 viewDidLayoutSubviews 中更改框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆