ios - 如何为 addSubView : using Autolayout 设置动画

标签 ios objective-c autolayout

设置:在 UIViewController 内的屏幕上有一个 containerView(为简单起见,假设为 containerView占据整个屏幕)。

问题:创建一个 overlayView 并将其添加为 containerView 的 subview ,并对外观进行动画处理,使其从右侧动画到位置作为对用户操作的响应。

UIView *overlayView = [[UIView alloc] initWithFrame:containerView.frame];
overlayView.translatesAutoresizingMaskIntoConstraints = NO;
[containerView addSubview:overlayView]; // Can't add constraints before inserting into view hierarchy

方法:将 overlayView 的前缘与 containerView 的前缘联系起来,我将其称为 >overlayLeadingConstraint。将 overlayLeadingConstraint.constant 设置为 containerView 的宽度,使其最初位于屏幕右侧。

NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[overlayView(width)]" options:0 metrics:metrics views:views];
[containerView addConstraints:constraints];
NSLayoutConstraint *overlayViewLeadingConstraint = [constraints objectAtIndex:0];
overlayViewLeadingConstraint.constant = containerView.frame.size.width;
// Height constraint not shown for simplicity

动画:现在进入真正的问题;将 overlayView 设置为从右侧开始的动画。第一种方法是这样的:

overlayViewLeadingConstraint.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
    [containerView layoutIfNeeded];
}];

但这不起作用,因为上面的所有代码都将在同一个运行循环中执行,因此只会显示最终结果。

第二种方法:尝试将动画推迟到 future 的运行循环,直到 addSubview: 已经发生的初始布局之后。

dispatch_async(dispatch_get_main_queue(), ^{
    overlayViewLeadingConstraint.constant = 0.0;
    [UIView animateWithDuration:1.0 animations:^{
        [containerView layoutIfNeeded];
    }];
});

这也不起作用,它暗示 addSubview: 和约束的设置可以占用多个运行循环。

第三种方法:尝试进一步延迟动画: future 的几个运行循环。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    overlayViewLeadingConstraint.constant = 0.0;
    [UIView animateWithDuration:1.0 animations:^{
        [containerView layoutIfNeeded];
    }];
}];

时间延迟很小,但它允许在动画之前完成多个运行循环,这似乎达到了预期的效果。

问题: 上述方法似乎是一种解决方法,而不是真正的 解决方案。所以我想知道是否有更好的方法来解决这个问题。我考虑过使用托管 viewControllerviewDidLayoutSubviews 方法来了解 overlayView 何时到位并且可以启动动画,但文档明确反对这样做:

However, this method being called does not indicate that the individual layouts of the view's subviews have been adjusted. Each subview is responsible for adjusting its own layout.

我开始认为 Apple 的想法是在初始化时添加所有 subview ,然后隐藏那些您不需要立即使用的 subview 。因此,当需要为 subview 设置动画时,它已经是 View 层次结构的成员,并与约束正确绑定(bind)。

你会怎么做?非常感谢任何输入。

最佳答案

我不确定您对某些未显示的内容做了什么,但这段代码对我来说效果很好。我在 IB (containerView) 中创建了一个 200 x 200 的 View ,并使用了这段代码,

 - (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIView *overlayView = [UIView new];
    overlayView.backgroundColor = [UIColor redColor];
    overlayView.translatesAutoresizingMaskIntoConstraints = NO;
    [containerView addSubview:overlayView];
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[overlayView]|" options:0 metrics:nil views:@{@"overlayView":overlayView}];
    NSArray *constraints2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[overlayView]|" options:0 metrics:nil views:@{@"overlayView":overlayView}];
    [containerView addConstraints:constraints];
    [containerView addConstraints:constraints2];
    NSLayoutConstraint *overlayViewLeadingConstraint = [constraints objectAtIndex:0];
    overlayViewLeadingConstraint.constant = containerView.frame.size.width;
    [containerView layoutIfNeeded];

    overlayViewLeadingConstraint.constant = 0.0;
    [UIView animateWithDuration:1.0 animations:^{
        [containerView layoutIfNeeded];
    }];
}

此动画正确。请注意,我在动画 block 之前调用了 layoutIfNeeded。在您的情况下,这可能是必要的,也可能不是必要的,具体取决于您未显示的代码的某些方面。

我不知道使用[constraints objectAtIndex:0] 来获取要修改的约束是否安全;它在这种情况下有效,但我不知道是否可以保证使用视觉格式设置的约束的顺序。

关于ios - 如何为 addSubView : using Autolayout 设置动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27927212/

相关文章:

ios - 更改嵌套 NSMutableDictionary 中的值

ios - 与 View 高度成比例的底部空间限制

swift - 尝试调整我的 UIView 容器的大小以适应较小的 iPhone 屏幕尺寸

ios - 使用 Storyboard 中的自动布局更改横向 View 框架

ios - 为什么一个普通的网页在 iOS 上会被放大?

ios - ScrollView 上绘制的线条不是滚动的?

javascript - 在 iOS 应用程序的 Parse Cloud Code 上运行 crypto-js 时出现问题

ios - 使用约束将按钮移向目标,没有反应?

iphone - 如何替换旋转和缩放的 UIImageView 中的图像?

ios - 如何禁用 "Implicit"或自动动画