Декабрь 2015

ТОМ 30, НОМЕР 13

Xamarin - Создание кросс-платформенной пользовательской среды с помощью Xamarin.Forms

Кит Пижиновски | Декабрь 2015

Продукты и технологии:

Xamarin.Forms, C#, Visual Studio, iOS, Android, Windows Phone

В статье рассматриваются:

  • два основных подхода Xamarin к созданию «родных» приложений, имеющих общий код: традиционный (Traditional Xamarin) и Xamarin.Forms;
  • подход Traditional Xamarin, который применяется, если приложению требуется специализированное взаимодействие на каждой платформе и использование множества специфичных для конкретной платформы API;
  • Xamarin.Forms, которая является полнофункциональной инфраструктурой для создания «родных» приложений для трех платформ из единой общей кодовой базы.

Исходный код можно скачать по ссылке

Если вы решили поэкспериментировать с Xamarin, значит, вы решили отправиться в увлекательное путешествие. В отличие от других средств разработки, которые привязывают вас к одной платформе, Xamarin открывает вам доступ к четырем платформам. С помощью Xamarin вы можете применить свои имеющиеся навыки в работе с C# для написания приложения под iOS, Android, Windows Phone и Mac OS X. Важно отметить, что Xamarin обеспечивает полный доступ к «родному» для платформы функционалу. Ваше приложение получает производительность, как у «родных» для конкретной платформы приложений, полный доступ к API на всех платформах и «родной» UI. В этой статье я сосредоточусь на трех мобильных платформах, поддерживаемых Xamarin: iOS, Android и Windows Phone.

Преимущества использования Xamarin впечатляют по многим причинам. Одна из причин в том, что работать с такой инфраструктурой, как Xamarin, сплошное удовольствие. Xamarin является игровой площадкой для более детального изучения всех этих платформ, в то же время позволяя применять имеющиеся у вас навыки в программировании на C#. Вместо работы в нескольких рабочих областях (Xcode, Android Studio/Eclipse и Visual Studio) с несколькими языками (C#, Java и Objective-C/Swift) вы можете использовать одну привычную среду (Visual Studio) с одним языком (C#).

С помощью Xamarin можно создать единственное решение, которое трансформируется в соответствующие версии вашего приложения для iOS, Android, Windows Phone и OS X.

Разработка приложений с применением Xamarin также дает несколько преимуществ в финансовом отношении. С помощью Xamarin можно создать единственное решение, которое трансформируется в соответствующие версии вашего приложения для iOS, Android, Windows Phone и OS X. Повторное использование кода и набора ваших навыков между этими платформами обеспечивает существенную экономию средств и повышение продуктивности труда. Когда дело доходит до монетизации вашего приложения, базовые законы экономики диктуют, что рост числа потенциальных клиентов создает больше возможностей в привлечении готовых платить потребителей. Совместно эти три мобильные платформы, поддерживаемые Xamarin, охватывают 98% всех мобильных устройств в мире.

Наконец, если вы создаете в своей организации мобильные специализированные бизнес-приложения (line-of-business, LOB), возможность создать решение для всех релевантных платформ означает, что ее сотрудники смогут использовать для работы свои устройства.

Подход Traditional Xamarin

Решение Traditional Xamarin, которое поддерживает все три мобильные платформы, состоит минимум из четырех проектов: Portable Class Library (PCL) и специфических для каждой платформы проектов. PCL (или проект с общим кодом) содержит модели, код для доступа к данным и бизнес-логику. На код в PCL можно ссылаться из других проектов и повторно использовать его в них. Однако PCL не содержат никакого UI-кода. UI-код поддерживается проектами, специфичными для конкретной платформы. Кроме того, важно отметить, что цель подхода Traditional Xamarin — обеспечить паритет функциональности с «родными» средами программирования и представляемыми ими платформами. Все, что можно сделать на Objective-C, Swift или Java, можно сделать и на C# с помощью Xamarin и Visual Studio. Доступен любой API, к которому вы хотите обращаться в iOS, Android и Windows Phone; Xamarin предоставляет доступ к 100% «родных» API. Этот код тоже находится в проектах, специфичных для конкретных платформ.

Хотя подход Traditional Xamarin позволит создавать большие объемы общего кода, есть способ сделать общим еще большее количество кода.

Знакомьтесь с Xamarin.Forms

Xamarin.Forms еще больше расширяет возможности повторного использования. В частности, Xamarin.Forms предоставляет все преимущества традиционного подхода и в то же время позволяет повторно использовать UI-логику между платформами. Решения Xamarin.Forms по-прежнему структурируются, как и решения Traditional Xamarin, но PCL теперь может содержать UI-код. Специфичные для платформы проекты все равно нужны для настроек проектов, хранения изображений и других ресурсов, различающихся на разных платформах.

Неудивительно, что ребята из Xamarin попытались добиться этого. Хотя iOS, Android и Windows Phone проектировались разными архитекторами и развивались под разными крышами, на внутреннем уровне в их UI много общего. Пользователи просматривают контент по одной странице единовременно. Многие элементы управления сходны на разных платформах. Например, текстовые поля, кнопки, переключатели, надписи, списочные представления и элементы управления изображениями относительно одинаковы на всех платформах. В целом, Xamarin.Forms поставляется с 40 элементами управления, семью разметками и пятью типами страниц для создания «родных» пользовательских сред (UX).

В Xamarin.Forms принята модель программирования на XAML/C#. Страницы, разметки и элементы управления можно декларативно создавать на XAML во многом по аналогии со страницами, создаваемыми в проекте Windows Phone. Все это также можно создавать полностью в коде. В этой статье будут показаны оба метода.

Xamarin.Forms еще больше расширяет возможности повторного использования.

При работе с Xamarin.Forms проектирование и реализация UI, который организует функции и контент вашего приложения, могут оказаться сложной задачей. Это нужно делать таким способом, который максимизирует повторное использование кода, в то же время позволяя получить приложение, естественное в использовании на каждой платформе. В связи с этим Xamarin предоставляет пять типов страниц для наиболее распространенных сценариев UI: страницы Content (для отображения базового контента), Navigation (для поддержки средств навигации), Tabbed (для создания страниц с вкладками вверху или внизу экрана), Master Detail (для отображения данных высокого уровня и более подробных данных в двух информационных панелях) и Carousel (для создания страниц с горизонтальной прокруткой контента). В этой статье будет продемонстрировано решение Xamarin.Forms с каждым из этих сценариев и обсуждением каждого из пяти типов страниц. Также будут показаны разметки страницы и UI-элементы управления, поставляемые с Xamarin.Forms.

Отображение контента

Отображение базового контента на экране осуществляется с помощью страницы Content. На рис. 1 приведен XAML для страницы, которая захватывает информацию от пользователей (user feedback).

Рис. 1. XAML для страницы Content

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="https://schemas.microsoft.com/winfx/2009/XAML"
  x:Class="XamarinFormsTestHarness.FeedbackPage"
  Title="Feedback">
  <StackLayout Padding="10,10,10,10">
<Label Text="Name:" FontAttributes="None" FontSize="Medium" TextColor="#3498DB"/>
  <Entry Text="{Binding Name}" Placeholder="First and Last" Keyboard="Default"/>
  <Label Text="Email:" FontSize="Medium" TextColor="#3498DB" />
  <Entry Text="{Binding Email}" Placeholder="name@company.com" Keyboard="Email" />
  <Label Text="Feedback:" TextColor="#3498DB" FontSize="Medium"/>
  <Editor Text="{Binding Text}" HeightRequest="200" BackgroundColor="Gray"/>
    <Button x:Name="ButtonSubmitFeedback" Text="Submit"
      BackgroundColor="#3498DB"
      TextColor="White"
      Command="{Binding SaveFeedbackCommand}"/>
  </StackLayout>
</ContentPage>

XAML на рис. 1 использует разметку «стопка» (stack layout) для организации базовых элементов управления, таких как Label, Entry, Editor и Button. В качестве примера возможностей Xamarin.Forms в поддержке «родного» функционала элемент Entry в iOS становится UITextField, в Android — EditText, а в Windows Phone — TextBox.

Предупреждение Xamarin XAML отличается от Windows Phone XAML. Нельзя взять XAML со страницы Windows Phone и поместить в страницу Content в Xamarin. Так, если вы привыкли использовать свойства Margin и Padding для тонкой подстройки позиций своих элементов управления, то будете разочарованы, узнав, что эти свойства во многих элементах управления Xamarin.Forms отсутствуют. Кроме того, многие элементы управления и их свойства имеют другие имена по сравнению со своими эквивалентами в Windows Phone. Эти расхождения могут показаться симптомом появления нового продукта. Зачастую это может быть правдой, но при этом не забывайте, что Xamarin предназначен не только для разработчиков под Windows Phone. Цель Xamarin — предоставить среду для разработчиков мобильных приложений с разным опытом. Если определенный элемент управления называется не так, как в Window Phone, все шансы за то, что его имя уходит корнями либо в Android, либо в iOS.

Страница Content является строительным блоком для всех остальных типов страниц. Страницы Carousel, Tabbed, Navigation и Master Detail используют страницы Content для создания своих UX.

Сценарии Master Detail

Сценарии Master Detail Scenarios очень распространены в мобильных приложениях. Поэтому Xamarin создала специфический тип страниц для этого сценария. Страница Master Detail (главная/подробная информация) может использоваться для организации функциональности или данных приложения. Например, в приложении, которое управляет клиентами и заказами, список клиентов можно показывать на странице Master. Как только пользователь указывает конкретного клиента, на странице подробностей могут отображаться все заказы, сделанные этим клиентом. Кроме того, страница Master Detail позволяет отображать команды меню приложения. В этом случае на странице Master выводится список функций, доступных в приложении, а каждая страница Detail предоставляет соответствующую функцию. На рис. 2 показан код конструктора страницы Master Detail, применяемой как основное меню в приложении для фитнеса, а на рис. 3 видно, как страница Master визуализируется на каждой платформе. Страница Master визуализируется в iOS и Android как боковое меню (popover menu), которое выскальзывает с левой стороны экрана. В Windows Phone она визуализируется как полноценная страница. Когда пользователь выбирает касанием какую-то команду (вариант), он попадает на соответствующую страницу.

Рис. 2. Код для страницы Master Detail

using System;
using Xamarin.Forms;
namespace XamarinFormsTestHarness
{
  public class MasterDetailControlPage : MasterDetailPage
  {
    public MasterDetailControlPage()
      {
      MenuPage menuPage = new MenuPage();
      menuPage.MenuListView.ItemSelected += (sender, e) =>
        MenuSelected(e.SelectedItem as MenuItem);
      // Вы должны задать страницу Detail, а иначе
      // произойдет крах страницы при визуализации
      this.Master = menuPage;
      this.Detail = new NavigationPage(new FeedbackPage());
      this.IsPresented = true;
      }
        ...
  }
}

Страница Master Detail, визуализируемая в iOS (слева), Android (в центре) и Windows Phone (справа)
Рис. 3. Страница Master Detail, визуализируемая в iOS (слева), Android (в центре) и Windows Phone (справа)

Чтобы понять код на рис. 2, стоит отметить несколько моментов. Прежде всего страница Master Detail на самом деле является контроллером. Она не содержит UX страницы Master или любой страницы Detail. Эти страницы находятся в отдельных файлах. Задача этого контроллера — показывать правильную страницу по требованию пользователя. На рис. 3 страница Master является страницей Content с именем MenuPage. Экземпляр MenuPage создается и записывается в свойство Master страницы Master Detail. XAML для MenuPage здесь не приведен для краткости. Вы найдете его в пакете исходного кода, сопутствующего этой статье. Страницы Master Detail на рис. 2 также не содержит UX для любой из страниц Detail. Они тоже находятся в отдельных файлах. Экземпляры страниц Detail создаются и записываются в свойство Detail страницы Master Detail, когда пользователь выбирает какую-то команду меню.

Цель Xamarin — предоставить среду для разработчиков мобильных приложений с разным опытом.

В конструкторе страницы Master Detail настраиваются и страница Master, и страница Detail. Страница Master Detail рухнет, если будет изначально показана без настроенных свойств обеих страниц.

Также важно понимать свойство IsPresented. Оно указывает, показывается ли пользователю страница Master. Если его значение — True, отображается страница Master, False — страница текущая страница Detail.

Windows Phone интерпретирует всю страницу Master как единое представление. Иначе говоря, когда пользователь переходит в представление Detail, Windows Phone не считает это навигацией по стандартным страницам. Коснувшись кнопки возврата в представлении Detail, пользователь попадает на страницу, которая показывалась до изначального перехода на страницу Master Detail. Это плохая UX, поскольку пользователь скорее всего ожидал возврата в представление Master страницы Master Detail. Чтобы обойти эту проблему, Xamarin.Forms позволяет переопределять событие OnBackButtonPressed. Это событие генерируется как в Windows Phone, так и в Android, так как на всех устройствах Windows Phone и Android есть кнопка возврата. И это событие не генерируется, если ваше приложение выполняется в iOS, поскольку в iOS нет такой кнопки. В iOS пользователь может вернуться на страницу Master, коснувшись значка этой страницы, который будет показываться в левом верхнем углу на всех страницах Detail. Важно всегда настраивать свойство icon страницы Master, а иначе пользователь окажется запертым на одной страниц Detail приложения безо всякой возможности вернуться на страницу Master.

Навигация в приложении

Страница Navigation управляет навигацией по страницам для iOS и Android. Эта навигация основана на том, что новая страница помещается вверх «стопки» страниц, а затем извлекается оттуда. Windows Phone отслеживает всю навигацию, и все устройства Windows Phone имеют аппаратную кнопку Back. Поэтому пользователь может всегда вернуться на предыдущий экран. Так что в Windows Phone страница Navigation не оказывает никакого эффекта.

Для iOS и Android страница Navigation предоставляет UX, которая показывает заголовок текущей страницы и заголовок предыдущей страницы как ссылку вверху. Корневая страница будет содержать только заголовок. Если пользователь касается заголовка предыдущей страницы, он возвращается на эту страницу.

Самый простой способ использовать страницу Navigation — создать ее экземпляр в коде и передать страницу в ее конструктор. В следующей строке кода создаются страницы Detail на рис. 2:

this.Detail = new NavigationPage(displayPage);

Страницы Navigation особенно важны в iOS, потому что устройства, на которых она работает, не имеют аппаратной кнопки Back. Без функционала, предоставляемого страницей Navigation, пользователи iOS не смогли бы возвращаться на одну страницу назад.

Вкладки

UI страницы с вкладками визуализируется как список вкладок либо вверху экрана, либо внизу. В iOS список вкладок появляется внизу экрана, а область подробностей (detail area) находится вверху. Если вкладок больше, чем может уместиться на экране, механизм рендеринга в iOS создаст вкладку More, которая открывает доступ к остальным вкладкам, не уместившимся на одном экране. В Android вкладки размещаются вверху экрана с областью подробностей внизу. Пользователь может горизонтально прокручивать набор вкладок, если он слишком велик, чтобы уместиться на экране. В Windows Phone страница с вкладками визуализируется как страница Pivot.

Страница Content является строительным блоком для всех остальных типов страниц.

Есть два способа создания страницы с вкладками. Первый способ: разработчики приложения могут поместить объекты Content Page в свойство Children страницы с вкладками, как показано на рис. 4. Для каждого элемента в наборе Children будет создано по одной вкладке. При создании вкладок используются свойства Title и Icon каждой страницы. Этот метод полезен, когда каждая вкладка выглядит по-своему и содержит свои данные. На рис. 5 видно, как визуализируется на каждой платформе страница с вкладками с рис. 4.

Рис. 4. Создание страницы с вкладками с помощью свойства Children

using Xamarin.Forms;
namespace XamarinFormsTestHarness
{
  class TabbedControlPage : TabbedPage
    {
    public TabbedControlPage()
      {
      this.Title = "My Workouts";
      this.Children.Add(new ThisWeek());
      this.Children.Add(new LastWeek());
      this.Children.Add(new ThisMonth());
      this.Children.Add(new LastMonth());
      this.Children.Add(new All());
      }
    }
}

Страница с вкладками, визуализируемая в iOS (слева), Android (в центре) и Windows Phone (справа)
Рис. 5. Страница с вкладками, визуализируемая в iOS (слева), Android (в центре) и Windows Phone (справа)

Другой способ создать страницу с вкладками — назначить список объектов, экземпляры которых созданы из одного и того же класса, свойству ItemsSource страницы с вкладками. Для каждого объекта в этом списке будет создано по одной вкладке. Затем DataTemplate должен быть записан в свойство ItemTemplate страницы с вкладками. DataTemplate создается из страницы Content, использующей связывание с данными для получения данных от соответствующего объекта в свойстве ItemSource. Важно связывать свойство Title этой страницы Content с каким-либо свойством в связанном объекте. Свойство Title будет использоваться для создания надписи на вкладке. Остальное содержимое этой страницы Content можно использовать для связывания с другими свойствами связанного объекта. Этот метод лучше подходит для страниц с вкладками, где каждая вкладка обеспечивает одну и ту же UX, но показывает разные данные.

UI страницы Carousel дает возможность пользователю проводить пальцем с одной боковой стороны экрана к другой, чтобы показывались другие страницы контента. Разработчики Windows Phone знают страницу Carousel как Panorama. Страница Carousel содержит свойство Children, как и страница с вкладками. Чтобы создать страницу Carousel, присвойте объекты страницы Content свойству Children страницы Carousel. Каждая страница Content будет визуализироваться как экран контента. Свойство Title каждой страницы Content в страницах Carousel не используется. (Этим они отличаются от страниц с вкладками, где свойство Title каждой вкладки отвечает за заголовок вкладки.) Поэтому, если вам нужна надпись для каждого экрана, вам понадобится реализовать это вручную как часть контента страницы Content. На рис. 6 показано, как страница Carousel визуализируется на каждой платформе. Заметьте, что в iOS и Android нет никакой видимой подсказки, информирующей пользователя о дополнительном контенте слева или справа от текущего представления. А в Windows Phone в качестве подсказки показывается часть заголовка страницы. По этой причине будьте осторожны в использовании Carousel на устройствах iOS и Android. Пользователи могут упустить важный контент вашего приложения.

Страница Carousel, визуализируемая в iOS (слева), Android (в центре) и Windows Phone (справа))
Рис. 6. Страница Carousel, визуализируемая в iOS (слева), Android (в центре) и Windows Phone (справа)

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

Дизайн для трех платформ

Если вы знакомы со всеми тремя платформами, то к этому моменту вы, по-видимому, уже поняли, что каждый из типов страниц в Xamarin.Forms представляет UI-сценарий, обязательный на одной из платформ, и креативно реализованный для остальных двух платформ. Например, страницы Navigation, которые предоставляют ссылку на предыдущую страницу, должны обеспечивать функциональность клавиши Back, отсутствующей в iOS. Страницы Navigation визуализируются в Android сходным образом, так как наличие ссылки на предыдущую страницу вверху текущей страницы отражает популярную структуру UI в Android, хотя на всех устройствах Android есть аппаратная кнопка Back.

Аналогично страницы Tabs весьма часто применяются как в iOS, так и в Android. Поэтому Xamarin.Forms нужно было иметь эту структуру UI в своем арсенале. В Windows Phone вкладки визуализируются как страницы Pivot, являющиеся важной частью этой ОС.

Страницы Master Detail предоставляют боковую панель (popover panel), которая иногда используется в iOS и Android.

Наконец, в Windows Phone есть концепция страницы Panorama. Такая страница лучше всего подходит в качестве начальной для приложения. Идея страницы Panorama — обеспечить представление верхнего уровня приложения. Страница Panorama с хорошо продуманным дизайном выглядит как обложка журнала. Она дает пользователю представление о том, что находится внутри. Если ее содержимое привлекательно оформлено, Panorama глубже затягивает пользователя в приложение. Горизонтальное смахивание для смены экранов контента — непривычный сценарий в iOS и Android. А значит, вы должны с осторожностью использовать страницу Carousel в приложении Xamarin.Forms.

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

Заключение

Xamarin предлагает два основных подхода к созданию «родных» приложений с общим кодом: Traditional Xamarin и Xamarin.Forms. Выбор конкретного подхода зависит от того, что именно вы разрабатываете.

Используйте подход Traditional Xamarin, когда вашему приложению требуется специализированное взаимодействие на каждой платформе и применение многих специфичных для платформы API. Traditional Xamarin также обеспечивает мощь в создании UI, адаптированных под каждую платформу.

Xamarin.Forms — это полнофункциональная инфраструктура для создания «родных» приложений, использующих одну общую кодовую базу. Подумайте о применении Xamarin.Forms, если вы создаете прототип, приложение для ввода данных или приложение, требующее небольшого подмножества функциональности, специфичной для платформы. Xamarin.Forms также является удачным выбором для проектов, где совместное использование кода важнее отдельного UI для каждой платформы.


Кит Пижиновски (Keith Pijanowski) — предприниматель и инженер. Имеет более чем 20-летний опыт работы в индустрии ПО. Работал в начинающих и крупных компаниях на самых разных должностях и занимался всем — от написания кода до развития бизнеса. С ним можно связаться по адресу keithpij@msn.com или через Twitter (@keithpij).

Выражаю благодарность за рецензирование статьи эксперту Xamarin Пирсу Боггэну (Pierce Boggan).