Как отклонить модал, который был представлен в UIStoryboard с модальным переходом? - PullRequest
32 голосов
/ 16 марта 2012

Настройка: у меня настроена раскадровка с двумя простыми контроллерами представления A и B. В A есть кнопка, которая переходит в B с модальным переходом.B представлен модальным переходом поверх A. Это нормально.

Вопрос: есть ли способ убрать B и вернуться к A с помощью простой магии раскадровки?

Обратите внимание, чтоесли бы все это было в навигационном контроллере, и я использовал push-segue, навигационный контроллер неявно позаботился бы о нем.Там будет кнопка «назад».Нет ничего похожего на модалы, мне нужно самому создать пользовательский интерфейс, но мне интересно, есть ли механика перехода, которую я могу использовать, чтобы сигнализировать, чтобы вернуться от B к A.

Теперь метод oldskoolЧтобы вернуться из B в A, можно создать:

  • создать свойство делегата в B
  • установить A в качестве делегата B, когда воспроизводится переход модального перехода (я могу подключиться кэто с использованием prepareForSegue: sender: в коде A)
  • когда пришло время отклонить, B сигнализирует своему делегату
  • A реализует метод делегата, который отклоняет B

Это работает, но кажется, что это слишком накладно и глупо.

Есть ли какая-то механика UIStoryboard, которую я пропустил, которая в основном делала бы "обратный модальный переход"?

Ответы [ 2 ]

44 голосов
/ 16 марта 2012

Нет никакого волшебства раскадровки для отклонения контроллера модального представления без написания хотя бы небольшого количества кода.

Но хотя вам действительно нужно реализовать какой-то собственный код, вам не обязательнодолжны пойти на это много неприятностей.Вы можете просто иметь кнопку в контроллере представления B, которая вызывает [self dismissViewControllerAnimated:YES completion:nil].(В документах говорится, что должен быть отклонен контроллер представления, но также говорится, что сообщение будет перенаправлено в контроллер представления, если он вызван на слушателя. Если вы хотите быть более откровенным об этом - и вы 'Это может понадобиться в некоторых случаях, например, когда один контроллер модального представления представлен из другого - вы можете явно сослаться на докладчика с помощью self.presentingViewController и вызвать dismiss... оттуда.)

Вы видите бизнес делегатав некоторых приложениях, потому что это один из способов уведомления контроллера представления A о том, что пользователь делал в режиме просмотра контроллера B ... но это не единственный способ.Есть KVO, уведомления или просто вызов методов A после обращения к нему с помощью self.presentingViewController (при условии, что B знает, что A всегда его представляет).И если A не нужно знать о том, что произошло в B (скажем, из-за того, что пользователь нажал кнопку «Отмена»), в этом нет необходимости - вы можете просто отклонить модал и покончить с этим.


В iOS 6 и более поздних версиях для раскручивания сегментов добавлена ​​еще одна опция, обеспечивающая немного «магии раскадровки» для отклонения контроллеров модального представления (или иным образом «отклонение» последовательности сегментов).Но этот подход все еще требует некоторого кода - вы не можете установить его полностью в раскадровке.С другой стороны, этот код обеспечивает путь для получения информации от отклоняемого контроллера представления (B) к представившему его (A).

У Apple есть техническая заметка о раскручиванииsegues , который охватывает их подробно, но вот краткая версия:

  1. Определите метод IBAction в классе контроллера представления, который вы хотите развернуть в - тот, который представляет модальный контроллер вида, а не сам модальный контроллер вида (вид контроллера А в вашем вопросе).В отличие от обычных IBAction методов, они должны принимать параметр типа UIStoryboardSegue *;например,

    - (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender
    
  2. В представленном контроллере представления (B в вопросе) подключите элемент управления к зеленому значку выхода и выберите метод, который вы определили.

  3. В реализации метода раскрутки вы можете обратиться к sourceViewController, чтобы получить информацию от отклоняемого контроллера представления.Вам не нужно вызывать dismissViewControllerAnimated:completion:, потому что segue обрабатывает отклонение контроллера представления, который уходит.

30 голосов
/ 16 июня 2013

Там - это магия раскадровки для достижения этой цели.Это известно как раскручивающийся переход.В файле .h вы реализуете любые методы стиля "target action", которые вам нужны, для сколь угодно большого количества переходов.Для модальных, это обычно два (отменить и сохранить).Таким образом, в моем файле Ah я бы добавил:

// A.h file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue;
- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue;

Теперь, в вашей раскадровке, если у вас есть переход от A к B. Теперь вы можете сделать перетаскивание элемента управления стилем "target action" из вашей отмены /сохранить кнопки в B в зеленый значок «Выход» в нижней части контроллера B в вашей раскадровке.Когда вы сделаете это, Xcode выберет два метода, которые мы создали (поскольку они находятся в заголовочном файле A и имеют правильную подпись (например, IBAction и UIStoryboardSegue *.), А B - это назначение перехода от A). Итак,там у вас есть это.У вас есть магия раскадровки, которую вы искали!

В реализации двух обратных вызовов у вас будет что-то вроде:

// A.m file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}

- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue {
    UIViewController *modalGoingAway = segue.sourceViewController;
    // Do something (like get data) from modalGoingAway if you need to...
}

Наконец, если этот подход отвечает вашим потребностям, отлично,Вы сделалиОднако я все еще подключаю весь шаблон проектирования делегата / источника данных протокола, если «при отмене» или «при сохранении» я хочу выполнить некоторые операции над частными свойствами B, прежде чем передать управление A, чтобы удалить B из иерархии представления.

...