动画期间子视图位置不正确

6
我有一个简单的动画,我正在从旧视图的中心扩展出一个新视图,同时该视图淡出。然而,这个新视图的子视图(一个按钮和一个标签)会从屏幕右下角飞入,当新视图扩展以占据整个屏幕时。我已经尝试开启或关闭自动布局,虽然两种情况会产生不同的结果,但它们都是错误的。
设置很简单,在故事板中有两个未连接的视图控制器,并使用以下代码来动画显示页面转换:
-(void)switchViews2:(id)sender {
    UIWindow *win = self.view.window;
    YellowController *yellow = [self.storyboard instantiateViewControllerWithIdentifier:@"Yellow"];
    yellow.view.frame = CGRectMake(0, 0, 1, 1);
    yellow.view.center = self.view.center;
    [win addSubview:yellow.view];
    CGRect  frame = self.view.frame;
    [UIView animateWithDuration:5 animations:^{
        yellow.view.frame = frame;
        self.view.alpha = 0;
    }
             completion:^(BOOL finished) {
                 [self.view removeFromSuperview];
                 win.rootViewController = yellow;
         }];
}

问题是,为什么子视图在其父视图动画过程中不能保持它们原本应该所在的位置。
2个回答

3
为了在使用自动布局时将子视图放置到正确的位置,最简单的方法是动画变换属性而不是框架。这样,子视图的边界属性不会改变,在动画期间不需要一直重新布局其子视图。
您可以使用最终框架添加子视图,然后将其变换设置为缩放仿射变换(例如0.1),最后将其动画到恒等变换。这样,它将从中心点开始增长,并且所有子视图都位于正确的位置。

谢谢,我对变换没有太多经验,所以往往会忘记使用这种方法。我想我应该多看一些相关资料。 - rdelmar

1
问题出在布局约束上。如果我不是在动画块中设置视图框架,而是在窗口和新视图之间添加约束,然后在动画块中调用layoutIfNeeded,那么它就可以正常工作:
-(void)switchViews2:(id)sender {
    UIWindow *win = self.view.window;
    YellowController *yellow = [self.storyboard instantiateViewControllerWithIdentifier:@"Yellow"];
    [yellow.view setTranslatesAutoresizingMaskIntoConstraints:NO];
    yellow.view.frame = CGRectMake(0, 0, 1, 1);
    yellow.view.center = self.view.center;
    [win addSubview:yellow.view];

    NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeLeading relatedBy:0 toItem:win attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
    NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeTop relatedBy:0 toItem:win attribute:NSLayoutAttributeTop multiplier:1 constant:20];
    NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeTrailing relatedBy:0 toItem:win attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
    NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeBottom relatedBy:0 toItem:win attribute:NSLayoutAttributeBottom multiplier:1 constant:0];

    [win addConstraints:@[con1,con2,con3,con4]];

    [UIView animateWithDuration:1 animations:^{
        [win layoutIfNeeded];
        self.view.alpha = 0;
    }
             completion:^(BOOL finished) {
                 [self.view removeFromSuperview];
                 win.rootViewController = yellow;
         }];
}

请注意,如果您正在使用完整形式的 animateWithDuration:delay:options:animations:completion:,您可以传递 UIViewAnimationOptionLayoutSubviews,它将为您执行 layoutIfNeeded - rob mayoff
1
@robmayoff,实际上在这种情况下那并不起作用。如果我包括那个选项,我将得不到任何动画 - 它会跳转到最终条件。 - rdelmar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接