it-swarm.com.ru

Содержимое попадает под панель навигации, когда внедряется в пользовательский контроллер представления контейнера.

ОБНОВЛЕНИЕ

Основываясь на ответе Тима, я реализовал следующее в каждом контроллере представления, который имел 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];
}

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

У меня есть собственный контроллер представления контейнера с именем SegmentedPageViewController. Я установил это как UINavigationController's rootViewController.

Назначение SegmentedPageViewController состоит в том, чтобы позволить UISegmentedControl, установленному как titleView NavController, переключаться между различными контроллерами дочерних представлений.

enter image description here

Эти дочерние контроллеры представления содержат либо представление прокрутки, представление таблицы или представление коллекции.

Мы находим, что первый контроллер представления загружается нормально, правильно расположен под панелью навигации. Но когда мы переключаемся на новый контроллер вида , Панель навигации не соблюдается, и представление устанавливается под панелью навигации.

enter image description here

Мы используем автоматическую разметку и построитель интерфейса. Мы перепробовали все, что могли придумать, но не можем найти последовательного решения.

Вот основной блок кода, отвечающий за настройку первого контроллера представления и переключение на другой, когда пользователь нажимает на сегментированный элемент управления:

- (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;
        }
    }

}
54
djibouti33

Ваш пользовательский контроллер представления контейнера должен будет отрегулировать contentInset второго контроллера представления в соответствии с вашей известной высотой панели навигации, учитывая свойство automaticallyAdjustsScrollViewInsets дочернего контроллера представления. (Возможно, вас также заинтересует свойство topLayoutGuide вашего контейнера - убедитесь, что оно возвращает правильное значение во время и после переключения представления.)

UIKit удивительно непоследователен (и глючит) в том, как он применяет эту логику; иногда вы увидите, что он выполняет эту настройку автоматически за счет достижения нескольких контроллеров представления вниз по иерархии, но часто после пользовательского переключения контейнера вам придется выполнять работу самостоятельно.

26
Tim

Кажется, все это намного проще, чем то, что люди разглядывают.

UINavigationController будет устанавливать вставки scrollview только во время размещения подпредставлений. Однако addChildViewController: не вызывает макет, поэтому после его вызова вам просто нужно вызвать setNeedsLayout на вашем навигационном контроллере. Вот что я делаю, переключая представления в пользовательском представлении в виде вкладок:

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

Последняя строка приведет к пересчету вставок scrollview для содержимого нового контроллера представления.

22
Dag Ågren

К сведению, если у кого-то возникла подобная проблема: эта проблема может возникнуть даже без встроенных контроллеров представления. Похоже, что automaticallyAdjustsScrollViewInsets применяется только в том случае, если ваш scrollview (или tableview/collectionview/webview) является первым представлением в иерархии контроллера их представления.

Я часто добавляю UIImageView первым в моей иерархии, чтобы получить фоновое изображение. Если вы сделаете это, вы должны вручную установить Edge вставки в scrollview в viewDidLayoutSubviews:

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

}
9
BFar

Я нашел лучшее решение, используйте недокументированный метод UINavigationController.

#import <UIKit/UIKit.h>

@interface UINavigationController (ContentInset)


- (void) computeAndApplyScrollContentInsetDeltaForViewController:(UIViewController*) controller;

@end

#import "UINavigationController+ContentInset.h"

@interface UINavigationController()


- (void)_computeAndApplyScrollContentInsetDeltaForViewController:(id)arg1; 

@end


@implementation UINavigationController (ContentInset)

- (void) computeAndApplyScrollContentInsetDeltaForViewController:(UIViewController*) controller
{
    if ([UINavigationController instancesRespondToSelector:@selector(_computeAndApplyScrollContentInsetDeltaForViewController:)])
        [self _computeAndApplyScrollContentInsetDeltaForViewController:controller];
}

@end

тогда делай так

- (void) cycleFromViewController: (UIViewController*) oldC
                toViewController: (UIViewController*) newC
{
    [oldC willMoveToParentViewController:nil];                        
    [self addChildViewController:newC];
  
    [self transitionFromViewController: oldC toViewController: newC   
                              duration: 0.25 options:0
                            animations:^{
                                newC.view.frame = oldC.view.frame;                                    
                                [self.navigationController computeAndApplyScrollContentInsetDeltaForViewController:newC];
                            }
                            completion:^(BOOL finished) {
                                [oldC removeFromParentViewController];                  
                                [newC didMoveToParentViewController:self];
                            }];
}

0
liaofc

Установка edgesForExtendedLayout = [] на моих дочерних контроллерах работала для меня.

0
coyer