Как переводчик заранее прошу извинения за возможные ошибки в переводе. Буду признателен сообщениям об ошибках для их скорейшего исправления.

Как я могу добавить панель бокового меню в свое iOS-приложение? Это один из самых часто задаваемых вопросов которые мы получаем от своих читателей. Сегодня мы покажем как создать боковое меню вроде того, которое вы можете наблюдать, например, в приложении от Facebook.

Для тех кто не знаком с понятием бокового меню в мобильных приложениях, Кен Ярмост (Ken Yarmost) дал хорошее объяснение этому элементу интерфейса и определил его как:
Боковое меню представляет собой панель, которая «выезжает» снизу, слева или справа от области основного контента приложения, содержащая вертикальную, независимую от основного контента приложения прокрутку, и служит основным инструментом навигации в приложении.

С того момента как Facebook представил боковое меню в своем мобильном приложении, этот элемент интерфейса быстро стал стандартом реализации навигации по приложению. В том или ином виде вы можете видеть боковое меню в таких популярных приложениях как Path, Mailbox, Gmail, Evernote и т.д.



Использование бокового меню, позволяет реализовать навигацию не отнимая драгоценного места у основного контента на экране мобильного устройства, потому что в неактивном состоянии такое меню скрывается за слоем основного контента приложения. Меню может быть вызвано путем нажатия кнопки меню на навигационной панели. После того как меню стало активным, пользователь может закрыть его, используя ту же кнопку меню на панели навигации или просто свайпом влево по области активного контента приложения.

При огромном количестве решений на GitHub, мы не станем строить свое боковое меню с нуля. Вместо этого мы воспользуемся замечательной библиотекой SWRevealViewController. Разработанная Джоном Ллучем (John Lluch), это бесплатная библиотека предоставляющая быстрый и простой способ реализации бокового меню.

Что ж, давайте попробуем разработать пример приложения вместе.

Обзор демонстрационного приложения


Как обычно мы разработаем демонстрационное приложение для того чтобы показать вам как использовать библиотеку SWRevealViewController. Приложение очень простое и его основная цель провести вас через процесс реализации бокового меню в вашем iOS-приложении. Наше навигационное меню будет работать следующим образом:

  • Меню вызывается нажатием кнопки «меню» в левом верхнем углу навигационной панели;
  • Также меню может быть вызвано свайпом вправо по активной области контента;
  • Пользователь может закрыть активное боковое меню, нажатием кнопки «меню» в левом верхнем углу навигационной панели;
  • Также меню может быть закрыто свайпом влево по активной области контента.



Создаем проект в XCode


С представлением основной идеи приложения мы двигаемся дальше. Вы можете создать проект Xcode с нуля и спроектировать пользовательский интерфейс, похожий на тот, что приведен ниже:



Однако, чтобы сэкономить время, вы можете скачать шаблон проекта XCode, который уже включает в себя:

  • Готовый storyboard со всеми необходимыми нам контроллерами;
  • Готовыми классами контроллеров вида, включая MapViewController и PhotoViewController;
  • MapViewController реализующий отображение карт;
  • PhotoViewController реализующий отображение фотографий и изображений;
  • Все необходимые приложению иконки и изображения (спасибо бесплатным иконкам от Pixeden)


Импорт библиотеки SWRevealViewController


Как уже упоминалось, мы будем использовать бесплатную библиотеку 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 из библиотеки объектов. Установите размер 38x38 и установите изображение «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</a>;
        photoController.photoFilename = photoFilename;
    }
}


В приведенном выше коде, мы сначала получаем идентификатор текущей ячейки и устанавливаем его в качестве заголовка для навигационной панели. Для сигвеев с идентификатором «showPhoto», контроллер вида отображения фотографий будет отображать только одну фотографию. В этом коде мы задаем имя файла изображения, которое мы будем отображать. Например, когда пользователь выберет пункт «Comments», мы покажем «comments_photo.jpg».

Заключительная компиляция и тестирование приложения


Теперь снова скомпилируйте и протестируйте приложение. Откройте боковое меню и выберите пункт «Map». Вы будете направлены в раздел отображающий карту. Попробуйте протестировать переход по другим пунктам меню и посмотрите что получилось.



Подведем итоги


В этом уроке мы показали вам как применять SWRevealViewController для реализации панели бокового меню на подобии приложения от Facebook. На GitHub можно найти много других решений реализации подобного меню, такие как GHSidebarNav и ViewDeck. Вы можете свободно исследовать другие библиотеки и выбирать те которые лучше всего подходят для ваших приложений. Если же вы хотите узнать как построить свое боковое меню с нуля, Рэй Вандерлич (Ray Wenderlich) предлагает замечательный урок.

Комментарии (26)


  1. And1ty
    08.04.2015 00:59
    +1

    Только ни в коем случае не используйте ViewDeck, он устаревший и в нем множество багов. Есть другие хорошие альтернативы, например MMDrawerController.


    1. Shannon
      09.04.2015 00:58

      Еще хороший вариант — AMSlideMenu, он мне понравился больше, так как получилось проще интегрировать
      Есть даже пошаговая видео-инструкция для storyboard — youtu.be/y33t_bWS_Zk


      1. And1ty
        09.04.2015 11:49

        Сталкивался с ним. Не особо он хорош — есть проблемы при поворотах с открытым меню и то что он делает в категории над UIViewController — свизлит appearance-методы и dealloc. Для бокового меню, мне кажется, это чересчур.


        1. Shannon
          10.04.2015 00:12

          Где-то пол-года назад отправлял исправление автору, так что при поворотах с тех пор всё нормально

          На счет через чур или нет, не знаю (перед использованием, изучал его на излишний перерасход памяти и утечки — всё в порядке), мне в проекте со storyboard удобнее именно AMSlideMenu интегрировать и использовать, чем MMDrawerController, но тут это уже дело вкуса


  1. itruf
    08.04.2015 01:16
    +3

    Мне кажется, что не нужны статьи про каждый опен сорсный контрол. Вы бы рассказали, как сделать самостоятельно — была бы хоть какая-нибудь польза.


    1. Splean Автор
      08.04.2015 01:26

      Во-первых, в конце моего перевода есть ссылка на урок создания подобного решения с нуля. Во-вторых, подобные пошаговые уроки позволяют начинающим быстрее и четче усвоить 1) принцип работы со сторонними библиотеками и интеграции их в свои проекты, 2) взаимодействия объектов приложения друг с другом, 3) приемы работы со средой разработки, ну и так далее… К сожалению русскоязычный интернет не богат на подобные мануалы и будь их больше, я уверен, это повысило бы общее качество приложений.
      Как-то так :)


      1. jonic
        08.04.2015 19:10

        Не слушай, пиши, переводи, не важно. Удобно, это еще и обучает азам работы с xCode.


  1. rsi
    08.04.2015 04:10

    Буквально неделю назад сидел и читал эту статью в оригинале, а английский не так силен. Переводите больше статей, особенно по актуальным инструментам, очень мало информации на русском.

    Еще очень хотелось бы увидеть статью о правильной организации приложения. Все примеры набрасываются на коленке, для демонстрации конкретной фичи, и не дают новичкам понимания, как делать это все правильно.


  1. OutLander
    08.04.2015 09:32
    +4

    <зануда мод> На прошлогоднем WWDC посвятили целый кусок презентации объяснению: почему не надо использовать Hamburger menu в своих приложениях. Посмотрите на все топ приложения, уже практически все ушли от его использования. </зануда мод>


    1. max_sokolov
      08.04.2015 10:21

      Подскажите пожалуйста, в какой презентации WWDC это упоминается?


      1. OutLander
        08.04.2015 12:26
        +2

        1. max_sokolov
          08.04.2015 12:27

          Большое спасибо!


    1. rsi
      08.04.2015 10:22

      А можно пару тезисов и пример приложений. Пробежался по всем топовым приложениям, везде присутствует данное меню


      1. OutLander
        08.04.2015 12:28

        Viber, например. Не пользуюсь соц. сетями, но, насколько помню, Twitter и Facebook тоже убрали его из приложений.


        1. max_sokolov
          08.04.2015 12:30

          Facebook все еще использует боковое меню. FB Messenger нет.


          1. OutLander
            08.04.2015 12:38
            +1

            Возможно. Zomato еще.
            В свое время мы принимали решение использовать Hamburger или нет и иммено рекомендации Apple стали ключевыми. Но это для энтерпрайз проложения, в котором навигацию просто так потом поменять не выйдет.


            1. max_sokolov
              08.04.2015 12:43

              Собственно интересует тот же вопрос. Хочется следовать лучшим практикам. Еще раз спасибо за ссылку выше.


    1. Splean Автор
      08.04.2015 11:38

      Ну знаете-ли, не угнаться за этими хипстерами ))


      1. OutLander
        08.04.2015 12:42

        Ну этому видео уже скоро год… Не сказал бы что прям новизна-новизна.


  1. ZverArt
    08.04.2015 09:48

    А подобная статья про Swift есть? На английском их всего несколько. Если у меня получится реализовать, то переведу.


    1. Splean Автор
      08.04.2015 11:37

      Да, вот swift-версия урока на той же самой библиотеке.


      1. ZverArt
        08.04.2015 12:38

        Как раз эту страницу открыл в браузере)


  1. aivs
    08.04.2015 11:39

    Спасибо за перевод, как раз искал варианты боковой панельки!


  1. stanislavfeldman
    08.04.2015 16:37

    Советую ECSlidingViewController.
    Меню добавляется очень легко в storyboard с помощью custom segues.


  1. fiveze
    09.04.2015 14:38

    Пользуюсь iOS-Slide-Menu.
    Достаточно указать левый/правый вид меню и слайдер готов.


  1. ZverArt
    21.04.2015 13:50

    Нужна такая же статья о создании такого меню на Swift?