【发布时间】:2015-01-13 16:46:59
【问题描述】:
设置:在屏幕上的UIViewController 内有一个containerView(为简单起见,假设containerView 占据整个屏幕)。
问题:创建overlayView 并将其添加为containerView 的子视图,并对外观进行动画处理,使其从右侧动画到某个位置,作为对用户操作的响应。
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];
}];
但这不起作用,因为上面的所有代码都会在同一个运行循环上执行,因此只会显示最终结果。
第二种方法:尝试将动画推迟到未来的运行循环,直到addSubview: 之后的初始布局已经发生。
dispatch_async(dispatch_get_main_queue(), ^{
overlayViewLeadingConstraint.constant = 0.0;
[UIView animateWithDuration:1.0 animations:^{
[containerView layoutIfNeeded];
}];
});
这也不起作用,它暗示addSubview: 和约束的设置可能会占用多个运行循环。
第三种方法:尝试进一步延迟动画:未来的几个运行循环。
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 何时到位并且可以启动动画,但文档明确建议不要这样做:
但是,调用此方法并不表示各个布局 视图的子视图已调整。每个子视图负责 调整自己的布局。
我开始认为 Apple 的想法是在初始化时添加所有子视图,并立即隐藏那些您不需要的。因此,当需要为 subView 设置动画时,它已经是与约束正确绑定的视图层次结构的成员。
你会怎么做?非常感谢任何意见。
【问题讨论】:
标签: ios objective-c autolayout