embedded在自定义容器视图控制器中时,内容落在导航栏下方。

UPDATE

基于Tim的回答,我在每个视图控制器中都实现了以下function,这些控制器具有作为我自定义容器一部分的滚动视图(或子类):

- (void)didMoveToParentViewController:(UIViewController *)parent { if (parent) { CGFloat top = parent.topLayoutGuide.length; CGFloat bottom = parent.bottomLayoutGuide.length; // this is the most important part here, because the first view controller added // never had the layout issue, it was always the second. if we applied these // edge insets to the first view controller, then it would lay out incorrectly. // first detect if it's laid out correctly with the following condition, and if // not, manually make the adjustments since it seems like UIKit is failing to do so if (self.collectionView.contentInset.top != top) { UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0); self.collectionView.contentInset = newInsets; self.collectionView.scrollIndicatorInsets = newInsets; } } [super didMoveToParentViewController:parent]; } 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我有自定义容器视图控制器称为SegmentedPageViewController 。 我把它设置为一个UINavigationController's rootViewController

SegmentedPageViewController的目的是允许UISegmentedControl (设置为NavController的titleView)在不同的子视图控制器之间切换。

在这里输入图像说明

这些子视图控制器都包含scrollview,tableview或collection视图。

我们发现第一个视图控制器加载正确,正确定位在导航栏下方。 但是,当我们切换到一个新的视图控制器,不尊重导航栏,并在导航栏下设置视图。

在这里输入图像说明

我们正在使用自动布局和界面生成器。 我们尝试了所有我们能想到的方法,但找不到一致的解决scheme。

这里是主要的代码块,负责设置第一个视图控制器,当用户点击分段控件时切换到另一个:

 - (void)switchFromViewController:(UIViewController *)oldVC toViewController:(UIViewController *)newVC { if (newVC == oldVC) return; // Check the newVC is non-nil otherwise expect a crash: NSInvalidArgumentException if (newVC) { // Set the new view controller frame (in this case to be the size of the available screen bounds) // Calulate any other frame animations here (eg for the oldVC) newVC.view.frame = self.view.bounds; // Check the oldVC is non-nil otherwise expect a crash: NSInvalidArgumentException if (oldVC) { // **** THIS RUNS WHEN A NEW VC IS SET **** // DIFFERENT FROM FIRST VC IN THAT WE TRANSITION INSTEAD OF JUST SETTING // Start both the view controller transitions [oldVC willMoveToParentViewController:nil]; [self addChildViewController:newVC]; // Swap the view controllers // No frame animations in this code but these would go in the animations block [self transitionFromViewController:oldVC toViewController:newVC duration:0.25 options:UIViewAnimationOptionLayoutSubviews animations:^{} completion:^(BOOL finished) { // Finish both the view controller transitions [oldVC removeFromParentViewController]; [newVC didMoveToParentViewController:self]; // Store a reference to the current controller self.currentViewController = newVC; }]; } else { // **** THIS RUNS WHEN THE FIRST VC IS SET **** // JUST STANDARD VIEW CONTROLLER CONTAINMENT // Otherwise we are adding a view controller for the first time // Start the view controller transition [self addChildViewController:newVC]; // Add the new view controller view to the view hierarchy [self.view addSubview:newVC.view]; // End the view controller transition [newVC didMoveToParentViewController:self]; // Store a reference to the current controller self.currentViewController = newVC; } } } 

您的自定义容器视图控制器将需要根据您已知的导航栏高度来调整第二个视图控制器的contentInset ,并contentInset子视图控制器的automaticallyAdjustsScrollViewInsets属性。 (您也可能对您的容器的topLayoutGuide属性感兴趣 – 确保它在视图切换期间和之后返回正确的值。)

UIKit在如何应用这种逻辑方面显然是不一致的(和错误的) 有时你会看到它通过在层次结构中向下多个视图控制器自动执行此调整,但通常在自定义容器切换后,您需要自己完成这项工作。

这似乎比人们想象的要简单得多。

UINavigationController只会在布局子视图的时候设置scrollview的insets。 addChildViewController:不会导致布局,但是,所以在调用它之后,您只需要在navigationController上调用setNeedsLayout 。 以下是我在自定义选项卡式视图中切换视图时的操作:

 [self addChildViewController:newcontroller]; [self.view insertSubview:newview atIndex:0]; [self.navigationController.view setNeedsLayout]; 

最后一行将导致为新视图控制器的内容重新计算scrollview插图。

如果有人遇到类似的问题,即使没有embedded式视图控制器也可能发生此问题。 看起来,只有当您的scrollview(或tableview / collectionview / webview)是其视图控制器层次结构中的第一个视图时,才会应用automaticAdjustsScrollViewInsets。

我经常在我的层次结构中首先添加一个UIImageView以获得背景图像。 如果你这样做,你必须在viewDidLayoutSubviews中手动设置scrollview的边缘插入:

 - (void) viewDidLayoutSubviews { CGFloat top = self.topLayoutGuide.length; CGFloat bottom = self.bottomLayoutGuide.length; UIEdgeInsets newInsets = UIEdgeInsetsMake(top, 0, bottom, 0); self.collectionView.contentInset = newInsets; } 

我find了一个更好的解决scheme,使用UINavigationController的未公开的方法。

 #import <UIKit/UIKit.h> @interface UINavigationController (ContentInset) - (void) computeAndApplyScrollContentInsetDeltaForViewController:(UIViewController*) controller; @end