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 неспособность автоматической настройки вставки содержимого».

  • Как обнаружить прикосновение к NSTextAttachment
  • Перемещение строки состояния в iOS 7
  • IOS 7 - добавить приложение для наложения наложения
  • Сброс разрешения доступа к микрофону iOS 7
  • Тайная катастрофа iOS 7
  • iOS 7 - region.center устарел
  • NSClassFromString () всегда возвращает nil
  • iOS8 UITableView scolling возвращается при прокрутке вверх
  • iOS 7: UIWebView падает из-за исключения диапазона
  • UIPopoverController Width Not Setting
  • Внешний вид MFMessageComposeViewController iOS 7
  • Interesting Posts

    Как сохранить большое (60 МБ +) изображение в библиотеке фотографий?

    Как установить цвет текста держателя места для UITextField при сохранении его существующих свойств?

    API Withings – доступ к защищенным ресурсам

    Библиотека? Статическая? Динамический? Или Рамки? Проект внутри другого проекта

    Использование звукового устройства bluetooth в iOS7 без разрешения микрофона

    UIActivityViewController для обмена изображениями с WeChat не работает

    Ввод заголовка readonly в UITextField

    Режим просмотра iOS – IB

    Измените цвет кнопки удаления красного цвета по умолчанию в UITableViewCell при прокрутке строк или нажмите кнопку редактирования

    Как получить UIStackView для обновления своего макета?

    Кордова InAppPurchase: .getProducts () возвращает пустой массив

    Работа с автоматической компоновкой

    Требуется ли моему Mac-приложению применить ключ доступа к серверу?

    Как установить значок tabBarItem из AppDelegate.m (tabBarView не является корневым представлением)

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

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