Привет, iOS (несколько экранов): теперь подробнее

Предупреждение

Поддержка конструктора iOS была прекращена в Visual Studio 2019 версии 16.8 и Visual Studio 2019 для Mac версии 8.8. В Visual Studio 2019 версии 16.9 и Visual Studio для Mac версии 8.9 этот конструктор удален. Создавать пользовательские интерфейсы iOS рекомендуется непосредственно на Mac с помощью Xcode Interface Builder. Дополнительные сведения см. в статье Проектирование пользовательских интерфейсов с помощью Xcode.

В этом пошаговом руководстве мы создадим и запустим первое приложение Xamarin.iOS с поддержкой нескольких экранов. Пришло время для расширения знаний о навигации и архитектуре iOS.

В этом руководстве мы опишем шаблон MVC (модель-представление-контроллер) и его роль в архитектуре и навигации iOS. Затем мы подробно рассмотрим контроллер навигации и научимся использовать его для создания привычной навигации iOS.

Модель-представление-контроллер (MVC)

В руководстве Привет, iOS мы узнали, что у приложений iOS есть только одно окно, в которое контроллеры представления могут загружать свои иерархии представления содержимого. Во втором пошаговом руководстве по созданию приложения Phoneword мы добавим второй экран для нашего приложения и настроим обмен данными (список телефонных номеров) между экранами, как показано на следующей схеме:

This diagram illustrates passing data between two screens

В нашем примере данные собираются на первом экране, передаются из первого контроллера представления во второй и отображаются на втором экране. Такое разделение экранов, данных и контроллеров представлений соответствует шаблону MVC (Модель — представление — контроллер). В следующих разделах мы рассмотрим преимущества этого шаблона и его компонентов, а также применим его в нашем приложении Phoneword.

Преимущества шаблона MVC

Модель-представление-контроллер (MVC) — это шаблон проектирования, многократно используемое архитектурное решение типовых проблем или сценариев использования в коде. MVC — это архитектура для приложений с графическим интерфейсом пользователя (GUI). В этой архитектуре объектам приложения назначается одна из трех ролей: модель (данные или логика приложения), представление (интерфейс пользователя) и контроллер (код программной части). На следующей схеме показаны связи между тремя элементами шаблона MVC и пользователем:

This diagram illustrates the relationships between the three pieces of the MVC pattern and the user

Преимущество использования шаблона MVC в том, что он обеспечивает логическое разделение между разными частями приложения с графическим интерфейсом и упрощает повторное использование кода и представлений. Давайте начнем и рассмотрим каждую из трех ролей более подробно.

Примечание.

Шаблон MVC — это аналог структуры страницы ASP.NET или приложения WPF. В этих примерах представление — это компонент, который фактически отвечает за описание пользовательского интерфейса и соответствует странице ASPX (HTML) в ASP.NET или XAML в приложении WPF. Контроллер — это компонент, который отвечает за управление представлением, он соответствует коду программной части в ASP.NET или WPF.

Модель

Объект типа модель обычно описывает способ представления данных в конкретном приложении, которые должны отображаться или вводиться в представлении. Модель часто задается свободно, например, в нашем приложении Phoneword_iOS моделью является список номеров телефонов (в виде списка строк). Если мы создаем кроссплатформенное приложение, то код PhonewordTranslator мы можем совместно использовать как в iOS, так и в приложениях.Android. Можно считать, что общий код и есть модель.

Для MVC абсолютно неважно, как в модели хранятся данные и как обеспечивается доступ. Другими словами, MVC безразлично, как выглядят наши данные или как они хранятся, важно только, как данные представлены. Например, мы можем хранить данные в базе данных SQL, в облачном хранилище или просто использовать List<string>. В MVC в шаблон включается только способ представления данных сам по себе.

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

Примечание.

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

Представления

Представление — это компонент, отвечающий за отображение пользовательского интерфейса. Практически во всех платформах, использующих шаблон MVC, пользовательский интерфейс представляет собой иерархию представлений. Можно считать, что представление в MVC является иерархией с одним представлением (называемым корневым представлением) на верхнем уровне иерархии и любым количеством дочерних представлений в нем (называемыми подчиненными представлениями). В iOS компонент экрана "иерархия представления содержимого" соответствует компоненту "представление" в MVC.

Контроллер

Объект типа контроллер — компонент, который связывает все вместе и представлен в iOS классом UIViewController. Можно считать контроллер вспомогательным кодом для экрана или набора представлений. Контроллер отвечает за ожидание запросов от пользователя и возврат соответствующей иерархии представлений. Он ожидает запросы из представления (нажатие кнопки, ввода текста и т. д.) и выполняет соответствующую обработку, изменение и обновление представления. Контроллер также отвечает за создание или получение модели из любого существующего в приложении внутреннего хранилища данных и заполнение представления этими данными.

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

В приложении Phoneword мы использовали контроллер навигации для управления навигацией между несколькими экранами. Контроллер навигации — это специализированный класс UIViewController, представленный классом UINavigationController. Вместо управления одной иерархией представления содержимого контроллер навигации управляет другими контроллерами представления, а также своей собственной особой иерархией представления содержимого в виде панели инструментов навигации, которая включает в себя заголовок, кнопку возврата и другие дополнительные возможности.

Контроллер навигации часто используется в iOS и обеспечивает навигацию в основных приложениях, например в приложении Настройки, как показано на рисунке ниже:

The navigation controller provides navigation for iOS applications like the Settings app shown here

Контроллер навигации выполняет три основные функции:

  • Обеспечивает привязку при переходах вперед — контроллер навигации использует метафору иерархической навигации, согласно которой иерархии содержимого представления помещаются в стек навигации. Мы можем представить стек навигации в виде стопки игральных карт, в которой видна только самая верхняя карта, как показано на приведенной ниже схеме:

    This diagram illustrates navigation as a stack of cards

  • При необходимости отображает кнопку возврата — когда мы отправляем новый элемент в стек навигации, в строке заголовка может автоматически отображаться кнопка возврата, позволяющая при навигации возвращаться назад. Нажатие кнопки возврата извлекает текущий контроллер представления из стека навигации и загружает в окно предыдущую иерархию представлений содержимого:

    This diagram illustrates popping a card off the stack

  • Отображает строку заголовка — верхняя часть контроллера навигации называется заголовком. Он отвечает за отображение заголовка контроллера представления, как показано на следующей схеме:

    The Title Bar is responsible for displaying the view controller title

Корневой контроллер представления

Контроллер навигации не управляет иерархией представлений содержимого, поэтому сам по себе он ничего не отображает. Вместо этого контроллер навигации сопряжен с корневым контроллером представления:

A navigation controller is paired with a Root view controller

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

The Sourceless Segue sets the first screens view controller as the Root view controller

Дополнительные возможности навигации

Контроллер навигации является стандартным способом управления навигацией в iOS, но существуют и другие способы. Например, контроллер панели вкладок может разделить приложение на различные функциональные области, а контроллер разделения представления может использоваться для создания основного и подробного представлений. Объединение контроллеров навигации с другими принципами навигации позволяет получить гибкие возможности для представления содержимого и навигации по содержимому в iOS.

Обработка переходов

В руководстве по созданию приложения Phoneword мы обрабатывали переходы между двумя контроллерами представлений двумя способами — сначала с раскадровкой перехода, а затем программными средствами. Рассмотрим оба этих способа более подробно.

PrepareForSegue

Когда мы добавляем переход к раскадровке при помощи действия Show, мы даем команду операционной системе iOS для отправки второго контроллера представления в стек контроллеров навигации:

Setting the segue type from a dropdown list

Добавления перехода в раскадровку достаточно для создания простого перехода между экранами. Если нам необходимо передавать данные между контроллерами представления, то необходимо переопределить метод PrepareForSegue и обрабатывать данные самим:

public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);
    ...
}

iOS вызывает метод PrepareForSegue непосредственно перед выполнением перехода и передает в метод созданный нами в раскадровке объект перехода. На этом этапе нам нужно вручную задать для перехода целевой контроллер представления. Следующий код получает дескриптор контроллера представления назначения и приводит его к необходимому классу, в данном случае к классу CallHistoryController:

CallHistoryController callHistoryController = segue.DestinationViewController as CallHistoryController;

Наконец, мы передаем список номеров телефонов (модель) из ViewController в CallHistoryController, присвоив свойству PhoneHistory класса CallHistoryController список набранных номеров телефонов:

callHistoryController.PhoneNumbers = PhoneNumbers;

Ниже приведен полный код для передачи данных с помощью объекта перехода:

public override void PrepareForSegue (UIStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    var callHistoryController = segue.DestinationViewController as CallHistoryController;

    if (callHistoryController != null) {
         callHistoryController.PhoneNumbers = PhoneNumbers;
    }
 }

Создание перехода от первого контроллера представления ко второму при помощи кода совпадает с созданием перехода при помощи объекта Segue, но необходимо выполнить некоторые действия вручную. Во-первых, воспользуемся методом this.NavigationController, чтобы получить ссылку на контроллер навигации, в стеке которого мы сейчас находимся. Затем с помощью метода контроллера навигации PushViewController вручную отправим в стек следующий контроллер представления, передавая контроллер представления и параметр для анимации перехода (установим его в значение true).

Следующий код обрабатывает переход с экрана Phoneword на экран журнала звонков:

this.NavigationController.PushViewController (callHistory, true);

Прежде чем мы сможем перейти к следующему контроллеру представления, нам нужно создать его экземпляр вручную из раскадровки, вызвав метод this.Storyboard.InstantiateViewController и передав идентификатор раскадровки CallHistoryController:

CallHistoryController callHistory =
this.Storyboard.InstantiateViewController
("CallHistoryController") as CallHistoryController;

Наконец, мы передаем список номеров телефонов (модель) из ViewController в CallHistoryController, присвоив свойству PhoneHistory класса CallHistoryController список набранных номеров телефонов, как мы это делали, когда обрабатывали переход при помощи Segue:

callHistory.PhoneNumbers = PhoneNumbers;

Ниже приведен полный код программного перехода:

CallHistoryButton.TouchUpInside += (object sender, EventArgs e) => {
    // Launches a new instance of CallHistoryController
    CallHistoryController callHistory = this.Storyboard.InstantiateViewController ("CallHistoryController") as CallHistoryController;
    if (callHistory != null) {
     callHistory.PhoneNumbers = PhoneNumbers;
     this.NavigationController.PushViewController (callHistory, true);
    }
};

Дополнительные понятия, представленные в Phoneword

В приложении Phoneword представлено несколько понятий, не охваченных этим руководством. В их число входят следующие:

  • Автоматическое создание контроллеров представлений — когда мы вводим имя класса для контроллера представления на панели свойств, конструктор iOS проверяет, существует ли этот класс, и затем создает соответствующий класс контроллера представления. Дополнительные сведения об этой и других возможностях конструктора iOS см. в руководстве Введение в конструктор iOS.
  • Контроллер представления таблицы — CallHistoryController это контроллер представления таблицы. Контроллер представления таблицы содержит представление таблицы, наиболее распространенный макет и инструмент отображения данных в iOS. Обсуждение таблиц выходит за рамки данного руководства. Дополнительные сведения о контроллере представления таблицы см. в руководстве Работа с таблицами и ячейками.
  • Идентификатор Storyboard — указание этого идентификатора создает в Objective-C класс контроллера представления, содержащий код программной части этого контроллера в Storyboard. Мы используем ИД Storyboard для нахождения класса Objective-C и для создания экземпляра контроллера представления в Storyboard. Дополнительные сведения об идентификаторах раскадровок см. в руководстве Введение в раскадровки.

Итоги

Поздравляем! Вы создали свое первое приложение iOS с несколькими экранами!

В этом руководстве мы рассказали о шаблоне MVC и о том, как его использовать для создания приложений с несколькими экранами. Мы также изучили контроллеры навигации и их роль в работе навигации iOS. Теперь у вас есть прочные знания, необходимые для разработки своих собственных приложений Xamarin.iOS.

Далее в руководствах Введение в разработку мобильных приложений и Разработка кроссплатформенных приложений мы научимся создавать кроссплатформенные приложения с помощью Xamarin.