[Перевод] Добавляем панель бокового меню в свое iOS-приложение
Как переводчик заранее прошу извинения за возможные ошибки в переводе. Буду признателен сообщениям об ошибках для их скорейшего исправления.Как я могу добавить панель бокового меню в свое iOS-приложение? Это один из самых часто задаваемых вопросов которые мы получаем от своих читателей. Сегодня мы покажем как создать боковое меню вроде того, которое вы можете наблюдать, например, в приложении от Facebook.
Для тех кто не знаком с понятием бокового меню в мобильных приложениях, Кен Ярмост (Ken Yarmost) дал хорошее объяснение этому элементу интерфейса и определил его как:
Боковое меню представляет собой панель, которая «выезжает» снизу, слева или справа от области основного контента приложения, содержащая вертикальную, независимую от основного контента приложения прокрутку, и служит основным инструментом навигации в приложении.
С того момента как Facebook представил боковое меню в своем мобильном приложении, этот элемент интерфейса быстро стал стандартом реализации навигации по приложению. В том или ином виде вы можете видеть боковое меню в таких популярных приложениях как Path, Mailbox, Gmail, Evernote и т.д.
Использование бокового меню, позволяет реализовать навигацию не отнимая драгоценного места у основного контента на экране мобильного устройства, потому что в неактивном состоянии такое меню скрывается за слоем основного контента приложения. Меню может быть вызвано путем нажатия кнопки меню на навигационной панели. После того как меню стало активным, пользователь может закрыть его, используя ту же кнопку меню на панели навигации или просто свайпом влево по области активного контента приложения.При огромном количестве решений на GitHub, мы не станем строить свое боковое меню с нуля. Вместо этого мы воспользуемся замечательной библиотекой SWRevealViewController. Разработанная Джоном Ллучем (John Lluch), это бесплатная библиотека предоставляющая быстрый и простой способ реализации бокового меню.
Что ж, давайте попробуем разработать пример приложения вместе.
Как обычно мы разработаем демонстрационное приложение для того чтобы показать вам как использовать библиотеку SWRevealViewController. Приложение очень простое и его основная цель провести вас через процесс реализации бокового меню в вашем iOS-приложении. Наше навигационное меню будет работать следующим образом: Меню вызывается нажатием кнопки «меню» в левом верхнем углу навигационной панели; Также меню может быть вызвано свайпом вправо по активной области контента; Пользователь может закрыть активное боковое меню, нажатием кнопки «меню» в левом верхнем углу навигационной панели; Также меню может быть закрыто свайпом влево по активной области контента. С представлением основной идеи приложения мы двигаемся дальше. Вы можете создать проект Xcode с нуля и спроектировать пользовательский интерфейс, похожий на тот, что приведен ниже:
Однако, чтобы сэкономить время, вы можете скачать шаблон проекта XCode, который уже включает в себя:
Готовый storyboard со всеми необходимыми нам контроллерами; Готовыми классами контроллеров вида, включая MapViewController и PhotoViewController; MapViewController реализующий отображение карт; PhotoViewController реализующий отображение фотографий и изображений; Все необходимые приложению иконки и изображения (спасибо бесплатным иконкам от Pixeden) Как уже упоминалось, мы будем использовать бесплатную библиотеку SWRevealViewController для реализации бокового меню. Сначала вам необходимо скачать библиотеку с GitHub и извлечь файлы из скачанного архива.После распаковки архива, вам необходимо найти файлы «SWRevealViewController.h» и «SWRevealViewController.m». Щелкните правой кнопкой мыши по папке SidebarDemo в окне навигатора проекта и создайте новую группу файлов, выбрав пункт «New Group» в раскрывшемся контекстном меню. Назовите группу «SWRevealViewController». Импортируйте оба файла в проект XCode, поместив их в группу «SWRevealViewController».
Одна из прекрасных особенностей библиотеки SWRevealViewController это встроенная поддержка Storyboard. При реализации бокового меню с помощью SWRevealViewController, разработчик должен связать SWRevealViewController с контроллерами видов основного контента приложения (верхний слой) и слоя бокового меню (подложка), используя сигвеи (segues). В нашем макете верхний слой — Navigation Controller, связанный с View Controller для отображения новостей, а нижний — View Controller содержащий меню навигации. Обычно меню реализуется с помощью UITableViewController.
В нашем шаблоне проекта для XCode уже созданы контроллеры видов для верхнего и нижнего слоев. Все что вам необходимо сделать — определить переходы (segues) между SWRevealViewController и контроллерами видов контента и подложки меню.
Для начала, выберите стартовый View Controller и измените его класс на «SWRevealViewController».
Затем, нажав и удерживая клавишу control на клавиатуре, щелкните по контроллеру вида SWRevealViewController и протащите курсор мыши до Menu View Controller. После того как вы отпустите клавишу, вы увидите контекстное меню для выбора сигвея (segue selection). В данном случае нам необходимо выбрать «reveal view controller set segue». Это определит пользовательский сигвей (segue) «SWRevealViewControllerSetSegue». Этот пользовательский переход (segue) сообщает SWRevealViewController о том что данный View Controller является исходным контроллером вида.
Примечание: Если вы используете старую версию SWRevealViewController, пожалуйста, обратите внимание, что использование SWRevealViewControllerSegue устарело и необходимо использовать SWRevealViewControllerSetSegue.
Повторите ту же самую процедуру для подключения к SWRevialViewController основного контроллера вида (основной вид содержащий новости).
Выберите сигвей между SWRevealViewController и Navigation Controller. Присвойте идентификатор «sw_front» для этого перехода в инспекторе атрибутов (attributes inspector). Это предопределенный идентификатор означающий переход к фронт-контроллеру представления (новости).
Для сигвея между SWRevealViewController и контроллера представления бокового меню, установите идентификатор «ws_rear». Этот идентификатор сообщает SWRevealViewController о том что этот контроллер представляет собой «подложку» (т.е. боковым меню).
Если вы скомпилируете и запустите приложение, то увидите приложение отображающего новости. И это все. Вы не увидите бокового меню, нажав на кнопку меню в левой части панели навигации. А все потому что мы еще не реализовали метод действия на нажатие этой кнопки.
Откройте «MainViewController.m», который является классом контроллера «News Frontpage». Добавьте следующую инструкцию импорта:
#import «SWRevealViewController.h» Затем добавьте следующий код в метод viewDidLoad:
SWRevealViewController *revealViewController = self.revealViewController; if (revealViewController) { [self.sidebarButton setTarget: self.revealViewController]; [self.sidebarButton setAction: @selector (revealToggle:)]; [self.view addGestureRecognizer: self.revealViewController.panGestureRecognizer]; } SWRevealViewController предоставляет метод revealToggle: для управления показом бокового меню. Как вы знаете, Cocoa использует механизм назначение-действие (target-action) для коммуникаций между контроллом и другими объектами. В качестве объекта-назначения для кнопки вызова меню мы установили View Controller панели навигации, а в качестве действия метод revealToggle:. Теперь, когда пользователь коснется кнопки показа бокового меню, будет вызван метод revealToggle:, который отобразит боковое меню. Наконец, мы добавили распознавание жеста. Теперь пользователь может вызвать меню не только нажатием кнопки, но и с помощью свайпа по области отображения основного контента приложения.
Попробуйте скомпилировать и выполнить приложение на симуляторе iPhone. Нажмите по кнопке «меню» и приложение должно показать вам выезжающее боковое меню. Нажмите на кнопку еще раз чтобы закрыть его. Так же вы можете открыть меню при помощи свайпа вправо.
Перед тем как продолжить, добавьте те же фрагменты кода в метод viewDidLoad: в файлах PhotoViewController.m и MapViewController.m. Приложение должно отображать боковую панель меню когда пользователь нажимает кнопку вызова меню и в этих двух конроллерах вида.
Всего лишь несколькими строчками кода вы реализовали выезжающее боковое меню. Здорово, не правда ли? Однако меню сейчас не содержит ни одного элемента. Мы добавим несколько пунктов меню и продемонстрируем вам реализацию перехода от одного пункта к другому. Для простоты примера, мы будем проектировать наше меню прямо в storyboard.
Первая ячейка таблицы содержит заголовок «APPCODA». Вы можете заменить этот заголовок на любой другой, по вашему усмотрению. Единственное что вы должны соблюдать, это идентификаторы ячеек, которые мы будем использовать в нашем коде впоследствии.
Хорошо, давайте добавим несколько пунктов меню. Для начала выберите прототип ячейки и в инспекторе атрибутов увеличьте количество прототипов до 8. В итоге вы должны получить экран аналогичный экрану ниже:
Измените надпись второй ячейки с«APPCODA» на «News». Если хотите, вы можете изменить цвет надписи на темно серый и изменить шрифт на «Avenir Next» в инспекторе атрибутов «Attributes inspector». Затем, переместите на ячейку image view из библиотеки объектов. Установите размер 38×38 и установите изображение «news.png» для этого объекта.
Затем, присвойте ячейке идентификатор «news» в инспекторе атрибутов. В итоге у вас должна получиться ячейка на подобии той что вы видите на изображении ниже:
Повторите те же самые процедуры для того чтобы получить следующие пункты меню:
Comments (изображение comments.png и идентификатор ячейки comments) Map (изображение map.png и идентификатор ячейки map) Calendar (изображение calendar.png и идентификатор ячейки calendar) Wishlist (изображение wishlist.png и идентификатор ячейки wishlist) Bookmark (изображение bookmark.png и идентификатор ячейки bookmark) Tag (изображение tag.png и идентификатор ячейки tag) Если вы все сделали верно, то ваша панель навигации будет выглядеть примерно так:
После завершения работы над пользовательским интерфейсом, давайте реализуем код для отображения ячеек таблицы навигации. Откройте файл «SidebarViewController.m» и добавьте в него следующую инструкцию импорта:
#import «SWRevealViewController.h» Затем, объявите переменную menuItems для хранения идентификаторов пунктов меню.
@implementation SidebarViewController { NSArray *menuItems; } Приведенный выше код очень прост. Мы инициализировали массив элементами-значениями идентификаторов ячеек пунктов меню. Затем откорректируйте метод numberOfSectionsInTableView: чтобы он возвращал 1 и метод numberOfRowsInSection: — он должен возвращать корректное количество строк в таблице:
— (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; }
— (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return menuItems.count; } Наконец, измените метод cellForRowAtIndexPath: следующим образом:
— (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *CellIdentifier = [menuItems objectAtIndex: indexPath.row]; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier forIndexPath: indexPath]; return cell; } Этот код просто получает идентификатор ячейки таблицы из массива menuItems для дальнейшего ее отображения. Теперь снова скомпилируйте и запустите приложение. Нажмите на кнопку отображения меню и на этот раз вы увидете панель навигационного меню, содержащего элементы.
Вы уже разработали приложение с визуально привлекательным боковым меню. Но мы кое-что упустили. Мы не определили ни одного перехода для пунктов меню. При выборе любого из пунктов меню, мы не переходим ни в одно из соответствующих представлений.Чтобы не усложнять демонстрационный пример, мы подключим к пунктам меню всего три контроллера вида. Думаю это очень хорошо продемонстрирует вам принцип работы. Вот что мы собираемся сделать:
Подключим ячейку с пунктом «News» к главному контроллеру вида, используя сигвей «reveal view controller push controller» Подключим ячейку с пунктом «Map» к контроллеру вида карты, используя сигвей «reveal view controller push controller» Все остальные ячейки пунктов меню будут связаны с контроллером вида просмотра фотографий, используя тот же вид сигвея. Однако для каждого пункта меню будет показана своя фотография. Итак, давайте вернемся к storyboard. Для начала выберите ячейку с идентификатором «map» (карта). Нажмите и удерживайте клавишу control на клавиатуре и щелкните по ячейкe «map». Протащите курсор мыши до контроллера вида отображения карты и выберите сигвей «reveal view controller push controller» в секции Selection Segue.
Повторите эту процедуру для ячейки «News», но соедините ее с главным контроллером вида.
Для каждого из пунктов меню comments, calendar, wishlist, bookmark и tag, подключите их один за одним к навигационному контроллеру контроллера вида отображения фотографий и каждому из созданных переходов присвойте идентификатор «showPhoto». Мы будем использовать этот идентификатор чтобы отличить эти сигвеи от двух предидущих.
После завершения конфигурирования сигвеев в storyboard, откройте «SidebarViewController.m». Для начала добавьте инструкцию импорта:
#import «PhotoViewController.h» Затем добавьте метод prepareForSegue: для управления переходом:
— (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Set the title of navigation bar by using the menu items NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController; destViewController.title = [[menuItems objectAtIndex: indexPath.row] capitalizedString]; // Set the photo if it navigates to the PhotoView if ([segue.identifier isEqualToString:@«showPhoto»]) { UINavigationController *navController = segue.destinationViewController; PhotoViewController *photoController = [navController childViewControllers].firstObject; NSString *photoFilename = [NSString stringWithFormat:@»%@_photo», [menuItems objectAtIndex: indexPath.row; photoController.photoFilename = photoFilename; } } В приведенном выше коде, мы сначала получаем идентификатор текущей ячейки и устанавливаем его в качестве заголовка для навигационной панели. Для сигвеев с идентификатором «showPhoto», контроллер вида отображения фотографий будет отображать только одну фотографию. В этом коде мы задаем имя файла изображения, которое мы будем отображать. Например, когда пользователь выберет пункт «Comments», мы покажем «comments_photo.jpg».
Теперь снова скомпилируйте и протестируйте приложение. Откройте боковое меню и выберите пункт «Map». Вы будете направлены в раздел отображающий карту. Попробуйте протестировать переход по другим пунктам меню и посмотрите что получилось.
В этом уроке мы показали вам как применять SWRevealViewController для реализации панели бокового меню на подобии приложения от Facebook. На GitHub можно найти много других решений реализации подобного меню, такие как GHSidebarNav и ViewDeck. Вы можете свободно исследовать другие библиотеки и выбирать те которые лучше всего подходят для ваших приложений. Если же вы хотите узнать как построить свое боковое меню с нуля, Рэй Вандерлич (Ray Wenderlich) предлагает замечательный урок.