嵌入自定义容器视图控制器时,内容位于导航栏下方.

dji*_*i33 55 objective-c uinavigationbar ios ios7

UPDATE

根据Tim的回答,我在每个视图控制器中实现了以下内容,该控制器具有作为自定义容器一部分的scrollview(或子类):

- (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];
}
Run Code Online (Sandbox Code Playgroud)

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

我有自定义容器视图控制器调用SegmentedPageViewController.我把它设为一个UINavigationController's rootViewController.

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

在此输入图像描述

这些子视图控制器都包含scrollview,tableview或集合视图.

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

在此输入图像描述

我们正在使用自动布局和界面构建器.我们已经尝试了我们能想到的一切,但找不到一致的解决方案.

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

- (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 (e.g. 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;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Tim*_*Tim 26

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

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

  • 我更新了我的问题.事实证明它不是关于使用viewWillLayout ..或willMoveToParentVC.这是关于意识到UIKit第一次做对了,之后失败了.在首先检查是否需要调整的条件中包装调整是票证.此外,通过这个解决方案,孩子们对自己负责,而容器vc并不担心它的显示对象.如果这很糟糕,你可以在容器中的viewWillLayout中做同样的事情,并在使用你建议的任何一种方法找到滚动视图后设置insets. (2认同)

Dag*_*ren 22

这似乎比人们所做的要简单得多.

UINavigationController仅在布局子视图时设置scrollview insets.addChildViewController:但是,不会导致布局,因此在调用它之后,您只需要调用setNeedsLayoutnavigationController.这是我在自定义选项卡式视图中切换视图时所做的事情:

[self addChildViewController:newcontroller];
[self.view insertSubview:newview atIndex:0];
[self.navigationController.view setNeedsLayout];
Run Code Online (Sandbox Code Playgroud)

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


BFa*_*Far 9

仅供参考,以防任何人遇到类似问题:即使没有嵌入式视图控制器,也会出现此问题.它似乎automaticallyAdjustsScrollViewInsets仅在滚动视图(或tableview/collectionview/webview)是其视图控制器层次结构中的第一个视图时应用.

我经常在我的层次结构中添加一个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;

}
Run Code Online (Sandbox Code Playgroud)