设置:在containerView
内的屏幕上显示UIViewController
(为简单起见,我们假设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
的{{1}}方法来了解viewDidLayoutSubviews
何时到位,并且可以启动动画,但文档明确建议不要这样做:
但是,调用此方法并不表示单个布局 该视图的子视图已经过调整。每个子视图负责 调整自己的布局。
我开始认为Apple的想法是在初始化时添加所有子视图,然后隐藏那些你不需要的子视图。因此,当为子视图设置动画时,它已经是视图层次结构的成员,并且与约束正确相关。
你会怎么做?任何意见都非常感谢。
答案 0 :(得分:5)
我不确定您对某些您不会展示的内容做了什么,但这段代码对我来说很好。我在IB(containerView)中创建了一个200 x 200的视图,并使用了这段代码,
- (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];
}];
}
这个动画正确。请注意,我在动画块之前调用了layoutIfNeeded。在您的情况下,这可能是必要的,也可能不是必需的,具体取决于您未能显示的代码的某些方面。
我不知道使用[constraints objectAtIndex:0]
获取您想要修改的约束是否安全;它适用于这种情况,但我不知道是否保证了使用可视格式设置的约束顺序。
答案 1 :(得分:1)
您尚未向要设置动画的animations
块添加任何内容。 animations
块通常被认为是“我希望我的UI最终处于这种状态;有效的东西可以实现这种效果”块。
[UIView animateWithDuration:1.0 animations:^{
overlayViewLeadingConstraint.constant = 0.0;
}];