Содержимое попадает под панель навигации при встраивании в пользовательский контроллер представления контейнера.
UPDATE
Основываясь на ответе Тима, я реализовал следующее в каждом контроллере представления, у которого был 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 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 rootViewController
.
Цель SegmentedPageViewController
- разрешить UISegmentedControl
, заданному как заголовок заголовка NavController, переключаться между различными контроллерами дочерних представлений.
![enter image description here]()
Все эти контроллеры детского представления содержат либо просмотр scrollview, tableview, либо коллекцию.
Мы обнаруживаем, что первый контроллер представления загружается нормально, правильно расположен под панелью навигации. Но когда мы переключаемся на новый
диспетчер просмотра, навигационная панель не соблюдается, и представление установлено под навигационной панелью.
![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;
}
}
}
Ответы
Ответ 1
Пользовательский контроллер просмотра контейнера должен будет настроить contentInset
второго контроллера представления в соответствии с вашей известной высотой навигационной панели, учитывая свойство automaticallyAdjustsScrollViewInsets
контроллера детского представления. (Вы также можете быть заинтересованы в свойстве topLayoutGuide
вашего контейнера - убедитесь, что он возвращает правильное значение во время и после переключателя вида.)
UIKit замечательно непоследователен (и глючит) в том, как он применяет эту логику; иногда вы увидите, что он автоматически выполняет эту настройку для вас, достигая нескольких контроллеров представления вниз в иерархии, но часто после настраиваемого переключателя контейнера вам нужно будет выполнить эту работу самостоятельно.
Ответ 2
Кажется, что все это намного проще, чем люди видят.
UINavigationController будет устанавливать вставки scrollview только при выделении подзонов. Однако addChildViewController:
не вызывает макет, поэтому после его вызова вам просто нужно вызвать setNeedsLayout
на вашем навигационном контроллере. Вот что я делаю при переключении просмотров в пользовательском табуляционном представлении:
[self addChildViewController:newcontroller];
[self.view insertSubview:newview atIndex:0];
[self.navigationController.view setNeedsLayout];
Последняя строка заставит scrollview-вставки перерасчитываться для нового содержимого контроллера.
Ответ 3
FYI, если у кого-то есть аналогичная проблема: эта проблема может возникнуть даже без встроенных контроллеров представления. Похоже, что automaticallyAdjustsScrollViewInsets
применяется только в том случае, если ваш scrollview (или tableview/collectionview/webview) является первым представлением в иерархии диспетчера своих представлений.
Я часто добавляю UIImageView сначала в свою иерархию, чтобы иметь фоновое изображение. Если вы это сделаете, вы должны вручную установить вставки в 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;
}
Ответ 4
Я нашел лучшее решение, используя недокументированный метод UINavigationController.
#import <UIKit/UIKit.h>
@interface UINavigationController (ContentInset)
- (void) computeAndApplyScrollContentInsetDeltaForViewController:(UIViewController*) controller;
@end