设置:在 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];
}];
}];
时间延迟很小,但它允许在动画之前完成多个运行循环,这似乎达到了预期的效果。
问题:
上述方法似乎是一种解决方法,而不是真正的 解决方案。所以我想知道是否有更好的方法来解决这个问题。我考虑过使用托管 viewController
的 viewDidLayoutSubviews
方法来了解 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/