Связывание контроллеров дочерних представлений с контроллером родительских представлений в раскадровке
можно ли связать дочерние контроллеры представления с пользовательским контроллером представления контейнера в раскадровке?
Я могу связать дочерние контроллеры вида с контроллером вида вкладки, и я могу связать один контроллер вида с навигационным контроллером.
Что я должен сделать с контейнером VC, чтобы принять дочерние VCs?
5 ответов:
как что-то из комбинации ответов Калеба и Мэтта, я сделал:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"cpdc_check_embed"]) { self.checkVC = segue.destinationViewController; } }...где
checkVC- это свойство контроллера контейнера:@property (weak,nonatomic) PXPCheckViewController * checkVC;вы просто должны установить
embedПродолжение ТУТStoryboard IDвсе, что вы хотите (в данном случае,cpdc_check_embed):
...а затем проверьте идентификатор в
-prepareForSegue:sender:.все еще не выход, но чище, чем у Мэтта (ИМХО) и более конкретный, чем у Калеба, и вы все еще получаете симпатичная раскадровка:
раскадровка имеет дело со встроенными контроллерами представления контейнера очень хорошо, отображая сегменты для дочерних / корневых контроллеров представления, так что отношения четко показаны. Также приятно, как дочерние и родительские контроллеры представления разделены на разные сцены.
если вы хотите достичь этого эффекта в своем собственном проекте, то есть трюк, который не является совершенным, но очень простой. В моем примере Предположим, что у меня есть контроллер представления контейнера, который действует как вкладка бар контроллер только с двумя вкладками, "левый" и "правый". Я хочу, чтобы сцена представляла контроллер родительского вида, а две отдельные сцены представляли как "левый" контроллер дочернего вида, так и "правый" контроллер дочернего вида.
хотя это невозможно, было бы неплохо, если бы я мог создать
IBOutlets от контроллера вида контейнера к его дочерним элементам в разных сценах, а затем, когда отображается мой контроллер вида контейнера, установите отношения родитель / потомок в соответствии к правилам, описанным в документация UIViewController. Если бы у нас были ссылки на наши "левые" и "правые" дочерние контроллеры представления, то мы могли бы установить отношения без проблем.стандартным решением этой проблемы ссылок является создание ссылок на дочерние контроллеры представления путем перетаскивания
Objectвыходы в сцену контроллера вида контейнера, а затем указание их типа класса как экземпляров дочернего контроллера вида занятия.чтобы держать детей разделенными в разных сценах, таких как встроенные контейнеры Apple, однако, мы будем использовать другой трюк. Во-первых, предположим, что у нас есть следующие свойства, объявленные в нашем классе контейнера,
ContainerViewController:@property (nonatomic, strong, readwrite) UIViewController *leftViewController; @property (nonatomic, strong, readwrite) UIViewController *rightViewController;в нашей раскадровке выберите сцену, представляющую "левый" контроллер вида. В инспекторе атрибутов установите контроллер вида
identifierсвойство"cvc_leftViewController"("cvc_" относится кContainerViewController, но действительно идентификатор может будьте все, что вы хотите). Сделайте то же самое для сцены правого контроллера вида, установив его идентификатор в"cvc_rightViewController".теперь вставьте следующий код в
ContainerViewController' sviewDidLoadспособ:if (self.storyboard) { _leftViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_leftViewController"]; _rightViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"cvc_rightViewController"]; }, когда
ContainerViewControllerзагружается из раскадровки, он будет захватывать "левый" и "правый" контроллеры вида из их соответствующих сцен и устанавливать ссылки на них через свои свойства. Теперь, когда у вас есть контроль над экземплярами контроллера дочернего представления, вы можете настроить родительский / дочерний отношения, как вам нравится. Чтобы узнать, как это сделать правильно, обратитесь к документация UIViewController.этот трюк не идеален и имеет много предостережений, но если вы будете осторожны, вы можете заставить его работать хорошо для вашего проекта.
Edit: хотя это совершенно не нужно и ничего не значит, если вы действительно действительно хотите, чтобы раскадровка отображала соединения из вашего контейнера с контроллерами дочерних представлений как и встроенные контейнеры Apple, просто используйте мой метод выше, а затем установите сегменты непосредственно между сценой контейнера и дочерними сценами и просто никогда не выполняйте эти сегменты. Теперь все будет работать правильно и выглядеть красиво тоже.
можно ли связать контроллеры дочерних представлений с пользовательским представлением контейнера контроллер в раскадровке?
Я думаю, что вы спрашиваете здесь, как подключить контроллер вида в одной сцене к розетке контроллера вида в другой сцене. Я не верю, что это возможно, возможно, потому что раскадровка машины не может иметь все сцены в раскадровке загружены в то же время.
вы, вероятно, спрашиваете об этом, потому что хотите передать некоторые информация от одного контроллера вида к другому при переходе от одной сцены к другой. Способ сделать это при работе с раскадровками-переопределить
-prepareForSegue:sender:в одном или обоих контроллерах представления, на которые влияет сегмент. Объект UIStoryboardSegue, предоставленный в иsourceViewControllerиdestinationViewControllerсвойства, а такжеidentifierсобственность. Эти свойства можно использовать для определения сегмента, который будет передавать данные между контроллерами представления.Ray Блог вендерлих имеет хороший двух частей учебное пособие по использованию раскадровки, которые могут помочь вам:
Часть 1 охватывает настройку проекта раскадровки, добавление сцен и создание сегментов.
Часть 2 имеет дело с использованием сегментов для перехода между сценами, в том числе
prepareForSequeметод, упомянутый выше.iOS 5 позволяет нескольким контроллерам просмотра быть активными в одной сцене (хотя один все еще должен быть ответственным), поэтому одна сцена в вашей раскадровке может иметь несколько контроллеров. Вы можете использовать розетки для подключения этих контроллеров друг к другу, и вы можете настроить эти соединения так же, как и в IB: control-перетаскивание с одного контроллера на другой в той же сцене. Обычный список розеток откроется, чтобы вы могли выбрать, какую розетку подключить.
ключ к использованию нескольких контроллеров в одной сцене (что я считаю, что вы здесь) использует таинственный объект из списка объектов в IB для представления другого контроллера вида и подключения его выходов.
ответ как создать пользовательский контейнер контроллера вида с помощью раскадровки в iOS 5 должно помочь, я надеюсь. Ответ также предоставляет рабочий пример приложения, которое очень полезно.
проблема с ответом @Ben (в противном случае разумным) заключается в том, что он работает только на одном уровне вложенности. Кроме того, потребуется, чтобы каждый последующий VC был настроен для сохранения контроллера вложенного представления в prepareForSegue.
чтобы решить эту проблему, я потратил слишком много времени на изучение индекса на основе NSObject, который вы могли бы добавить в раскадровку, привязать к сцене, а затем зарегистрировать его Родительский VC в Глобальном индексе на основе типа и restorationId. Эта работа / может работать, но слишком много усилий в конце концов, и по-прежнему требует двухэтапного процесса визуальной привязки и программного поиска.
для меня самое простое и общее решение-лениво спускаться по иерархии контроллера вида
в моем простом тестовом проекте я добавил следующие строки для viewDidLoad:
self.left.data = [ "Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro.", "De carne lumbering animata corpora quaeritis." ]здесь
leftопределено как:lazy var left:CollectionViewController = { [unowned self] in return self.childViewControllerWithId("Left") as! CollectionViewController }()и
childViewControllerWithIdопределено как:extension UIViewController { func childViewControllerWithId(rid:String) -> UIViewController? { // check immediate child controllers for vc in self.childViewControllers as! [UIViewController] { if vc.restorationIdentifier == rid { return vc } } // check nested controllers for vc in self.childViewControllers as! [UIViewController] { if let vc = vc.childViewControllerWithId(rid) { return vc } } assert(false, "check your assumptions") return nil } }обратите внимание, что вы могли бы сделать другие
findварианты, основанные на типе, если это необходимо. Также обратите внимание, что выше требуется определить идентификатор восстановления в файле раскадровки. Если бы у вас не было повторяющихся экземпляров одного и того же контроллера вида, то использование type было бы проще.и чтобы заявить, что, надеюсь, очевидно, вам не нужно реализовывать prepareForSegue, и вам не нужно использовать ленивую загрузку, вам просто нужно позвонить
find(...).

