iOS 7: Пользовательский контроллер представления контейнера и вставка содержимого

У меня есть контроллер табличного представления, завернутый в контроллер навигации. Кажется, что контроллер навигации автоматически применяет правильную вставку содержимого к контроллеру табличного представления, когда он представлен через presentViewController:animated:completion: (Может ли кто-нибудь объяснить мне, как это работает?)

Однако, как только я завершаю комбинацию в пользовательском контроллере представления контейнера и представляю, что вместо этого верхняя часть содержимого представления таблицы скрыта за панелью навигации. Есть ли что-то, что я могу сделать, чтобы сохранить поведение автоматической вставки содержимого в этой конфигурации? Должен ли я «пропустить» что-то в контроллере контейнера, чтобы это работало правильно?

Я бы хотел, чтобы избежать необходимости корректировки вставки содержимого вручную или с помощью автоматического макета, поскольку я хочу продолжать поддерживать iOS 5.

6 Solutions collect form web for “iOS 7: Пользовательский контроллер представления контейнера и вставка содержимого”

У меня была аналогичная проблема. Итак, на iOS 7 в UIViewController есть новое свойство, называемое automaticallyAdjustsScrollViewInsets . По умолчанию установлено значение YES . Когда ваша иерархия представлений каким-либо образом более сложна, чем просмотр прокрутки / таблицы внутри контроллера навигации или панели вкладок, это свойство, похоже, не работает для меня.

Я сделал это: я создал класс контроллера базового представления, который наследует все мои другие контроллеры. Этот диспетчер представлений затем позаботится о том, чтобы явно установить вставки:

Заголовок:

 #import <UIKit/UIKit.h> @interface SPWKBaseCollectionViewController : UICollectionViewController @end 

Реализация:

 #import "SPWKBaseCollectionViewController.h" @implementation SPWKBaseCollectionViewController - (void)viewDidLoad { [super viewDidLoad]; [self updateContentInsetsForInterfaceOrientation:self.interfaceOrientation]; } - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [self updateContentInsetsForInterfaceOrientation:toInterfaceOrientation]; [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; } - (void)updateContentInsetsForInterfaceOrientation:(UIInterfaceOrientation)orientation { if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) { UIEdgeInsets insets; if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { insets = UIEdgeInsetsMake(64, 0, 56, 0); } else if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { if (UIInterfaceOrientationIsPortrait(orientation)) { insets = UIEdgeInsetsMake(64, 0, 49, 0); } else { insets = UIEdgeInsetsMake(52, 0, 49, 0); } } self.collectionView.contentInset = insets; self.collectionView.scrollIndicatorInsets = insets; } } @end 

Это также работает для веб-просмотров:

 self.webView.scrollView.contentInset = insets; self.webView.scrollView.scrollIndicatorInsets = insets; 

Если есть более элегантный и надежный способ сделать это, пожалуйста, дайте мне знать! Значения жестко закодированных вставок плохо пахнут, но я не вижу другого способа, когда вы хотите сохранить совместимость с iOS 5.

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

Благодаря подсказке Йоханнеса Фаренкрюга, я понял следующее: automaticallyAdjustsScrollViewInsets действительно работает только так, как рекламируется, когда корневым представлением контроллера детского просмотра является UIScrollView . Для меня это означает, что работает следующая компоновка:

Контроллер содержимого внутри контроллера навигации внутри настраиваемого контроллера просмотра контейнера .

Хотя это не так:

Контроллер представления содержимого внутри настраиваемого контроллера просмотра контейнера внутри навигационного контроллера .

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

UINavigationController вызывает недокументированный метод _updateScrollViewFromViewController: toViewController при переходе между контроллерами для обновления вложений содержимого. Вот мое решение:

UINavigationController + ContentInset.h

 #import <UIKit/UIKit.h> @interface UINavigationController (ContentInset) - (void) updateScrollViewFromViewController:(UIViewController*) from toViewController:(UIViewController*) to; @end 

UINavigationController + ContentInset.m

 #import "UINavigationController+ContentInset.h" @interface UINavigationController() - (void) _updateScrollViewFromViewController:(UIViewController*) from toViewController:(UIViewController*) to; @end @implementation UINavigationController (ContentInset) - (void) updateScrollViewFromViewController:(UIViewController*) from toViewController:(UIViewController*) to { if ([UINavigationController instancesRespondToSelector:@selector(_updateScrollViewFromViewController:toViewController:)]) [self _updateScrollViewFromViewController:from toViewController:to]; } @end 

Вызовите updateScrollViewFromViewController: toViewController где-нибудь в вашем настраиваемом контроллере контейнера

 [self addChildViewController:newContentViewController]; [self transitionFromViewController:previewsContentViewController toViewController:newContentViewController duration:0.5f options:0 animations:^{ [self.navigationController updateScrollViewFromViewController:self toViewController:newContentViewController]; } completion:^(BOOL finished) { [newContentViewController didMoveToParentViewController:self]; }]; 

Вам не нужно вызывать какие-либо недокументированные методы. Все, что вам нужно сделать, это вызвать setNeedsLayout на вашем UINavigationController . См. Другой ответ: https://stackoverflow.com/a/33344516/5488931

Быстрое решение

Это решение предназначено для iOS 8 и выше в Swift.

Контроллер корневого представления моего приложения – это контроллер навигации. Первоначально этот навигационный контроллер имеет один UIViewController в своем стеке, который я буду называть контроллером родительского представления.

Когда пользователь нажимает кнопку навигационной панели, контроллер родительского представления переключает между двумя дочерними контроллерами представления на своем представлении с использованием API-интерфейса (переключение между отображаемыми результатами и перечисленными результатами). Контроллер родительского представления содержит ссылки на два дочерних контроллера. Второй контроллер детского представления не создается до тех пор, пока пользователь не закроет кнопку переключения. Второй контроллер детского представления – это контроллер табличного представления, и он обнаружил проблему, когда он перекрывает панель навигации независимо от того, как было установлено свойство autoAdjustsScrollViewInsets.

Чтобы исправить это, я вызываю adjustChild:tableView:insetTop (показано ниже) после создания контроллера представления дочернего табличного представления и в режиме viewDidLayoutSubviews контроллера родительского представления.

Представление таблицы контроллера topLayoutGuide.length представления и topLayoutGuide.length контроллера topLayoutGuide.length представления передаются в метод adjustChild:tableView:insetTop подобный этому …

 // called right after childViewController is created adjustChild(childViewController.tableView, insetTop: topLayoutGuide.length) 

Метод adjustChild …

 private func adjustChild(tableView: UITableView, insetTop: CGFloat) { tableView.contentInset.top = insetTop tableView.scrollIndicatorInsets.top = insetTop // make sure the tableview is scrolled at least as far as insetTop if (tableView.contentOffset.y > -insetTop) { tableView.contentOffset.y = -insetTop } } 

tableView.scrollIndicatorInsets.top = insetTop регулирует индикатор прокрутки в правой части таблицы, поэтому он начинается чуть ниже навигационной панели. Это тонко и легко упускается из виду, пока вы не узнаете об этом.

Ниже viewDidLayoutSubviews как выглядит viewDidLayoutSubviews

 override func viewDidLayoutSubviews() { if let childViewController = childViewController { adjustChild(childViewController.tableView, insetTop: topLayoutGuide.length) } } 

Обратите внимание, что весь приведенный выше код появляется в контроллере родительского представления.

Я понял это с помощью ответа Кристофера Пикслея на вопрос «iOS 7 Table view неспособность автоматической настройки вставки содержимого».

  • Приложение сбой во время ввода контроллера просмотра
  • Как сделать мой iOS7 UITableViewController НЕ отображаемым в верхней строке состояния?
  • `-webkit-overflow-scrolling: touch` сломан для первоначальных внеэкранных элементов в iOS7
  • iOS 7 Значительный запуск изменения местоположения после завершения
  • AFHTTPSessionManager отправляет запрос GET в формате json
  • RTCVideoCapturer capturerWithDeviceName: (NSString *) становится очень медленным после последующих вызовов
  • Как обрабатывать возврат / отмену покупки в приложении
  • Xcode 7 GM отсутствует симуляторы iOS 7
  • UIWebview рендеринг iOS 7
  • Неверный UISegmentedControl (потенциальная ошибка)
  • Как изменить цвет текста в UIPickerView под iOS 7?
  • Interesting Posts

    Кордова Раскройте раскадровку Изображения не переносятся

    Как получить все applicationActivities для UIActivityViewController?

    Использование делегата для передачи данных для резервного копирования стека навигации

    Как перезагрузить представление таблицы после вставки объекта в основные данные

    Ошибка входа в центр участника Apple

    переопределение shouldAutorotate не работает в Swift 3

    Невозможно принудительно настроить ориентацию UIViewController

    Текст Изменение анимации так же, как и предсказание текста клавиатуры ios 8

    UIButton с изображением и текстом

    Как я могу получить текущее местоположение на iOS?

    iOS: Является ли и связанные с ним методы управления уведомлениями потоком безопасными?

    OCR Tessearct Сканирование фрагментов текста не слева направо iOS

    Ошибка iphonesimulator (SDK не найдена) в xcode

    iOS In-App Purchase Нет Back-end

    Замена для stringByAddingPercentEscapesUsingEncoding в ios9?

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.