viewWillTransitionToSize safeArea 和 presentViewController
viewWillTransitionToSize safeArea and presentViewController
在屏幕旋转时,我需要重新计算一些内部视图。
我在那里嵌入了一个 UIViewController 和 UIScrollView。内部视图取决于 ScrollView 框架的大小。
所以在 UIViewController 中我有以下代码:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator {
DDLogDebug(@">>>>>>>>>>>>> %@", NSStringFromCGSize(size));
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
DDLogDebug(@"+++++++++ mainScroll %@", NSStringFromCGRect(_mainScroll.frame));
CGRect newFrame = CGRectMake(0, 0, size.width, size.height);
self.view.frame = newFrame;
[self.view.layer layoutIfNeeded];
DDLogDebug(@"--------- mainScroll %@", NSStringFromCGRect(_mainScroll.frame));
// and update the children
}
completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
}];
}
到目前为止一切顺利。我看到在手动将框架的大小设置为控制器的视图并调用 layoutIfNeeded(或 layoutSubviews - 相同的结果)后,mainScroll 大小得到适当调整,包括考虑 safeArea 约束,一切都很好。
现在,代码中某处有一个名为
的弹出控制器
[self presentViewController:controllerToPresent animated:NO completion:nil];
没什么有趣的,但是这个控制器在另一个控制器之上,我在上面描述过,而且 mainScroll 也在后台。
现在,尝试旋转屏幕会导致 layoutIfNeeded 之后的 mainScroll 的大小比没有弹出控制器时高 20 点。好像 safeArea guides/constraints 没有在后台应用。关闭弹出控制器后,mainScroll 比预期的要大,我的视图错位了......
有什么提示吗?
为什么 "presentViewController" 会影响调用者在 viewWillTransitionToSize 方面的行为?
为了应对挑战,我采用了以下解决方案:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
[self updateLayoutAfterRotation:size];
}
completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
}];
}
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
[self updateLayoutAfterRotation:self.view.frame.size];
}
- (void)updateLayoutAfterRotation:(CGSize)size {
CGRect newFrame = CGRectMake(0, 0, size.width, size.height);
self.view.frame = newFrame;
[self.view.layer layoutIfNeeded];
// Here is custom code to adopt layout
}
有趣的是,当这个 viewController 自行旋转时(屏幕上的俯视图),首先您会收到 viewSafeAreaInsetsDidChange
,然后是 viewWillTransitionToSize
。
但是如果控制器的视图隐藏在弹出控制器的后面,那么它的调用顺序就会相反。 viewSafeAreaInsetsDidChange
在弹出控制器关闭时首先调用(即不再在屏幕旋转时调用)
在屏幕旋转时,我需要重新计算一些内部视图。 我在那里嵌入了一个 UIViewController 和 UIScrollView。内部视图取决于 ScrollView 框架的大小。
所以在 UIViewController 中我有以下代码:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator {
DDLogDebug(@">>>>>>>>>>>>> %@", NSStringFromCGSize(size));
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
DDLogDebug(@"+++++++++ mainScroll %@", NSStringFromCGRect(_mainScroll.frame));
CGRect newFrame = CGRectMake(0, 0, size.width, size.height);
self.view.frame = newFrame;
[self.view.layer layoutIfNeeded];
DDLogDebug(@"--------- mainScroll %@", NSStringFromCGRect(_mainScroll.frame));
// and update the children
}
completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
}];
}
到目前为止一切顺利。我看到在手动将框架的大小设置为控制器的视图并调用 layoutIfNeeded(或 layoutSubviews - 相同的结果)后,mainScroll 大小得到适当调整,包括考虑 safeArea 约束,一切都很好。
现在,代码中某处有一个名为
的弹出控制器[self presentViewController:controllerToPresent animated:NO completion:nil];
没什么有趣的,但是这个控制器在另一个控制器之上,我在上面描述过,而且 mainScroll 也在后台。 现在,尝试旋转屏幕会导致 layoutIfNeeded 之后的 mainScroll 的大小比没有弹出控制器时高 20 点。好像 safeArea guides/constraints 没有在后台应用。关闭弹出控制器后,mainScroll 比预期的要大,我的视图错位了...... 有什么提示吗?
为什么 "presentViewController" 会影响调用者在 viewWillTransitionToSize 方面的行为?
为了应对挑战,我采用了以下解决方案:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
[self updateLayoutAfterRotation:size];
}
completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
}];
}
- (void)viewSafeAreaInsetsDidChange {
[super viewSafeAreaInsetsDidChange];
[self updateLayoutAfterRotation:self.view.frame.size];
}
- (void)updateLayoutAfterRotation:(CGSize)size {
CGRect newFrame = CGRectMake(0, 0, size.width, size.height);
self.view.frame = newFrame;
[self.view.layer layoutIfNeeded];
// Here is custom code to adopt layout
}
有趣的是,当这个 viewController 自行旋转时(屏幕上的俯视图),首先您会收到 viewSafeAreaInsetsDidChange
,然后是 viewWillTransitionToSize
。
但是如果控制器的视图隐藏在弹出控制器的后面,那么它的调用顺序就会相反。 viewSafeAreaInsetsDidChange
在弹出控制器关闭时首先调用(即不再在屏幕旋转时调用)