topLayoutGuide在子视图控制器中

我有一个UIPageViewController与半透明的状态栏和导航栏。 它的topLayoutGuide是64像素,正如所料。

但是, UIPageViewController的子视图控制器UIPageViewController报告0像素的topLayoutGuide ,即使它们显示在状态栏和导航栏下方。

这是预期的行为? 如果是这样,在真正的topLayoutGuide下定位子视图控制器视图的最好方法是什么?

(使用parentViewController.topLayoutGuide ,我认为这是一个黑客)

虽然这个答案可能是正确的,但我仍然发现自己不得不走上遏制树find正确的父视图控制器,并得到你所描述的“真正的topLayoutGuide ”。 这样我可以手动实现automaticallyAdjustsScrollViewInsets

这是我如何做到这一点:

在我的表视图控制器(实际上是UIViewController的子类),我有这样的:

 - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; _tableView.frame = self.view.bounds; const UIEdgeInsets insets = (self.automaticallyAdjustsScrollViewInsets) ? UIEdgeInsetsMake(self.ms_navigationBarTopLayoutGuide.length, 0.0, self.ms_navigationBarBottomLayoutGuide.length, 0.0) : UIEdgeInsetsZero; _tableView.contentInset = _tableView.scrollIndicatorInsets = insets; } 

注意UIViewController的类别方法,这是我实现它们的方法:

 @implementation UIViewController (MSLayoutSupport) - (id<UILayoutSupport>)ms_navigationBarTopLayoutGuide { if (self.parentViewController && ![self.parentViewController isKindOfClass:UINavigationController.class]) { return self.parentViewController.ms_navigationBarTopLayoutGuide; } else { return self.topLayoutGuide; } } - (id<UILayoutSupport>)ms_navigationBarBottomLayoutGuide { if (self.parentViewController && ![self.parentViewController isKindOfClass:UINavigationController.class]) { return self.parentViewController.ms_navigationBarBottomLayoutGuide; } else { return self.bottomLayoutGuide; } } @end 

希望这可以帮助 :)

您可以在故事板中添加一个约束,并在viewWillLayoutSubviews中进行更改

像这样的东西:

 - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; self.topGuideConstraint.constant = [self.parentViewController.topLayoutGuide length]; } 

我可能是错的,但在我看来,这种行为是正确的。 容器视图控制器可以使用topLayout值来布局其视图的子视图。

参考文献说:

要在不使用约束条件的情况下使用顶部布局指南,请获取指南相对于包含视图顶部边界的位置。

在父项中,相对于包含视图,值将是64。

在子视图中,相对于包含视图(父视图),值将为0。

在容器视图控制器中,你可以这样使用属性:

 - (void) viewWillLayoutSubviews { CGRect viewBounds = self.view.bounds; CGFloat topBarOffset = self.topLayoutGuide.length; for (UIView *view in [self.view subviews]){ view.frame = CGRectMake(viewBounds.origin.x, viewBounds.origin.y+topBarOffset, viewBounds.size.width, viewBounds.size.height-topBarOffset); } } 

子视图控制器不需要知道有一个导航和一个状态栏:它的父母将已经布置了它的子视图考虑到这一点。

如果我创build一个新的基于页面的项目,将其embedded到导航控制器,并将此代码添加到父视图控制器它似乎工作正常:

在这里输入图像说明

如果您使用的是UIViewController子类,文档说在viewDidLayoutSubviews中使用topLayoutGuide,如果使用的是UIView子类,则使用layoutSubviews。

如果你在这些方法中使用它,你应该得到一个合适的非零值。

文档链接: https : //developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/topLayoutGuide

如果你有像OP一样的UIPageViewController ,并且你有例如集合视图控制器作为孩子。 发现内容插件的修复很简单,它适用于iOS 8:

 - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; UIEdgeInsets insets = self.collectionView.contentInset; insets.top = self.parentViewController.topLayoutGuide.length; self.collectionView.contentInset = insets; self.collectionView.scrollIndicatorInsets = insets; } 

这已经在iOS 8中解决了。

如何设置子视图控制器的topLayoutGuide位置

从本质上说,容器视图控制器应像其他任何视图一样约束子视图控制器的(top|bottom|left|right)LayoutGuide 。 (在iOS 7中,它已经完全受到限制,所以这是行不通的。)

我认为这些指南肯定是为嵌套的子控制器设置的。 例如,假设你有:

  • 一个100×50的屏幕,顶部有一个20像素的状态栏。
  • 顶层视图控制器,覆盖整个窗口。 其topLayoutGuide是20。
  • 顶视图中的嵌套视图控制器覆盖底部95像素, 从屏幕顶部向下5个像素。 这个视图应该有一个15的topLayoutGuide,因为它的前15个像素被状态栏覆盖。

这是有道理的:这意味着嵌套的视图控制器可以设置约束,以防止不必要的重叠,就像一个顶层。 它不必关心它是嵌套的,还是父窗口显示在屏幕上的位置,父视图控制器不需要知道孩子想要如何与状态栏进行交互。

这似乎也是文档或者一些文档至less说的:

顶部布局指南指示视图控制器视图的顶部与覆盖视图的最底部酒吧的底部之间的距离(以磅为单位)

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UILayoutSupport_Protocol/Reference/Reference.html

这并不是说只为顶级视图控制器工作。

但是,我不知道这是真的发生了什么。 我已经看到子视图控制器与非零topLayoutGuides,但我仍然搞清楚怪癖。 (在我的情况下,顶部指南应该是零,因为视图不在屏幕的顶部,这是我现在正在撞我的头…)

这是已知引导长度的方法。 创build约束不是为了指导,而是在固定常数的情况下查看顶部,假设指导距离将会是。

@NachoSoto的Swifty执行回答:

 extension UIViewController { func navigationBarTopLayoutGuide() -> UILayoutSupport { if let parentViewController = self.parentViewController { if !parentViewController.isKindOfClass(UINavigationController) { return parentViewController.navigationBarTopLayoutGuide() } } return self.topLayoutGuide } func navigationBarBottomLayoutGuide() -> UILayoutSupport { if let parentViewController = self.parentViewController { if !parentViewController.isKindOfClass(UINavigationController) { return parentViewController.navigationBarBottomLayoutGuide() } } return self.bottomLayoutGuide } } 

不知道是否有人仍然有这个问题,因为我还在几分钟前。
我的问题是这样的 (来自https://knuspermagier.de/2014-fixing-uipageviewcontrollers-top-layout-guide-problems.html的源gif)。;
简而言之,我的pageViewController有3个子视图控制器。 第一个viewcontroller是好的,但是当我滑到下一个,整个视图不正确地偏移到顶部(约20像素,我猜),但将手指离开屏幕后恢复正常。
我熬夜寻找解决scheme,但仍然没有find一个运气。 然后突然间,我想出了这个疯狂的想法:

 [pageViewController setViewControllers:@[listViewControllers[1]] direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:^(BOOL finished) { }]; [pageViewController setViewControllers:@[listViewControllers[0]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished) { }]; 

我的listViewControllers有3个子视图控制器。 索引0处的问题有问题,所以我首先将其设置为pageviewcontroller的根,然后将其设置回第一个视图控制器(如我所料)。 瞧,它的工作!
希望能帮助到你!