Вступление
В недавно вышедшем iOS 5 появился удобный механизм разработки интерфейса программы — Storyboard. Этот механизм позволяет заметно уменьшить количество кода связанного с переходами между экранами, показами Popover'a и даже с настрокой ячеек в таблице.
Задача: По нажатию на кнопку показать следующий экран поместив его в текущий NavigationController.
Решение без Storyboard:
DDetailViewController* nextController = [DDetailViewController new];
[self.navigationController pushViewController:nextController animated:YES];
[nextController release];
Решение с использованием Storyboard:
![](https://habrastorage.org/storage1/ad700238/1a7b5407/a6eaa8d7/f2e62357.png)
Вот и все! Никакого кода!
Как это работает
В проекте создается файл .storyboard и весь интерфейс загружается из него. Внутри этого файла описана сцена.
![](https://habrastorage.org/storage1/97e1d2ab/b0b3573a/5a3aa095/10db12ba.png)
Такая стрелка указывает на самый первый экран, который будет виден при включении программы. Она добавляется автоматически, после добавления самого первого контроллера в Storyboard, в дальнейшем можно ее перетянуть на любой другой контроллер, тем самым сделав его первым.
![](https://habrastorage.org/storage1/dfdcf38b/d65cd6fd/6c6b9ede/af715482.png)
Эта стрелка описывает отношения между контроллерами, в данном случае rootViewController NavigationController'a соответствует FirstViewController. Эту связь можно задать так же как задаются связи аутлетов и экшенов (к примеру, можно провести линию от одного контроллера к другому с зажатым Ctrl).
![](https://habrastorage.org/storage1/c407166a/5bc614c6/35a4eb88/498dd7f0.png)
Такой стрелкой показывается переход на другой контроллер. Такой переход можно легко установить так же и как и предыдущем случаев, начало связи может идти сразу от нужного элемента интерфейса — кнопки, ячейки таблицы и тд. У нее есть настройки — идентификатор и тип перехода.
На первый взгляд все кажется очень тривиальным, но сразу встает вопрос, что же делать если надо передать данные при переходе из одного контроллера в другой?
Перехват показа экрана
Каждый переход между контроллерами описывается классом UIStoryboardSegue, в его интерфейсе всего три свойства: identifier, sourceViewController, destinationViewController. Именно этот клас и будет передан нам в метод
- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
Этот метод будет вызван у контроллера из которого был начат переход, в нашем случае это будет FirstViewController. Определим его следующим образом:
- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"showDetail"])
{
[[segue destinationViewController] setText:@"SecondViewController"];
}
else
{
[super prepareForSegue:segue sender:sender];
}
}
Значение identifier было задано в настройках перехода.
Storyboard на iPad
В айфоне одновременно может выполняться лишь одна сцена, то на айпаде есть исключения в виде поповеров. Для показа поповера используется класс UIStoryboardPopoverSegue, наследник UIStoryboardSegue. В этом класе добавлено одно свойство — popoverController, которое всегда возвращает поповер, в котором показывается текущая сцена.
Микс кода
Не во всех ситуациях переходы можно описать в Storyboard. В этом случае можно миксовать Storyboard со старыми, привычными методами отображения и перехода между контроллерами. Тут тоже есть небольшие упрощения:
- У класса UIViewController появились новые методы и свойства для работы со Storyboard, одно из них — storyboard, которое возвращает текущий Storyboard сцены.
- Если переход уже есть в Storyboard и ему задан идентификатор, то переход можно вызвать используя следующий метод принадлежащий UIViewController:
- (void)performSegueWithIdentifier:(NSString*)identifier sender:(id)sender
- Если перехода не описан в Storyboard, но описан контроллер, то можно вызвать его используя метод принадлежащий UIStoryboard:
- (id)instantiateViewControllerWithIdentifier:(NSString*)identifier
- В остальных случаях можно использовать старые методы.
Приятная мелочь
Как и обещал в самом начале статьи, теперь возможно настраивать UITableViewCell прямо в storyboard! Можно как выбирать из готовых типов ячеек так и делать полностью свои!
![](https://habrastorage.org/storage1/ad0d0443/eea15cef/11b0b73a/1d19a501.png)
Сомневаюсь в юзабилити такого интерфейса, но раньше у меня ушло бы на него куда больше времени. Если не определять методы UITableViewDataSource в контроллере, то табличка будет именно так же выглядеть в коде. Если же нам надо наполнять таблицу динамически, то используем старый код, за исключением того, что метод таблицы
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
теперь всегда возвращает ячейку. Если такой ячейки нету в очереди, то она будет создана.Как добавить Storyboard в проект
- Если создаете новый проект, то тут все просто — ставим галочку Use Storyboard.
- Если надо добавить новую часть интерфейса в существующий проект и захотелось попробовать Storyboard, то делаем следующее: добавляем новый файл в проект, в виззарде выбираем в секции iOS->User Interface тип файла Storyboard. Дальше используем класс UIStoryboard для создания сцены.
- Если хотим перевести весь интерфейс в существующем проекте на Storyboard, то делаем как в пукте выше, переносим туда весь интерфейс и обязательно в настройках проекта выбираем интересующий нас таргет и на вкладке Summary удаляем все в поле Main Interface и вписываем название сцены в Main Storyboard:
Заключение
Конечно, сейчас еще рано начинать интегрировать Storyboard в свои проекты, так как нужна поддержка более ранних версий, но технология выглядит заманчиво. Кроме того, если не хватает стандартных типов переходов, всего можно написать своего наследника UIStoryboardSegue.