【问题标题】:Changing a frame in viewDidLayoutSubviews更改 viewDidLayoutSubviews 中的框架
【发布时间】:2015-01-22 11:37:22
【问题描述】:

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

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

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

编辑:这是代码。在这里,我在viewDidLayoutSubviews 中调用prepareAppearance,这可行,但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) {
                         }];
    }
}

【问题讨论】:

    标签: ios objective-c uiview uiviewcontroller


    【解决方案1】:

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

    • 请勿更改/触摸viewDidLayoutSubviews
    • viewWillAppear 中添加逻辑以将元素移动到屏幕外(到它们的初始位置之前动画)
    • 添加逻辑以将元素动画到它们在viewDidAppear 中的正确位置

    更新

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

    在动画方法中更新约束后不要忘记调用[weakView layoutIfNeeded]

    【讨论】:

    • 我确实在问题中提到我已经尝试过!似乎viewDidAppear 中的 UI 尚未准备好,因此元素不会移到屏幕外
    • 但奇怪的是,动画确实有效!应该吗?
    • 是的。即使您有中心对齐约束,您也可以更改它们以将视图移出框架。
    • 它做到了!事实证明,使用约束制作动画解决了这个问题。 Apple 现在推荐使用约束的动画并不是没有原因的。我已经移植了我的动画来使用它。也为延迟接受答案道歉;我从来没有这样的动画,它需要一些阅读。感谢您的帮助。
    【解决方案2】:

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

    【讨论】:

    • 请仔细检查所有内容。 viewDidAppear 被称为after 视图已经出现,所以一切都必须是可见的并且已经布局。
    • 是的,我注意到了。在模拟器中它似乎运行良好,但在设备上它显示得更早。问题依然存在。
    • 请发布当前代码,以便我们查看。
    • @sha,代码不多。我有一个名为 prepareAppearance 的方法,它将视图移到屏幕外(没有动画),另一个名为 animateAppearance 的方法相反,但动画视图。机器人动画和设置工作正常,只是我打电话给他们的时间不正确。我也意识到问题是 viewDidLayoutSubviews 被调用 after viewWillAppear,这导致视图被重置到原来的位置。这就是它不起作用的原因。
    • 我放弃了。没有看到您的代码 - 没有必要进一步讨论这个问题。
    猜你喜欢
    • 2020-01-25
    • 2014-04-24
    • 1970-01-01
    • 2013-03-30
    • 1970-01-01
    • 1970-01-01
    • 2014-04-26
    • 1970-01-01
    相关资源
    最近更新 更多