Статьи

Введение в Xamarin: часть 3

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

Несколько лет назад, когда начали появляться многие кроссплатформенные решения, возникло и неправильное представление о Write Once Run Anywhere или WORA . Многие разработчики начали испытывать слюну при мысли о возможности писать свои приложения на одном языке и запускать его на различных мобильных платформах. Идея не является неправильной, она просто была слегка дезинформирована в начале.

Мечта о WORA становится реальностью, когда вы рассматриваете общую логику вашего приложения. Что считается общей логикой? Почти все, что не связано с пользовательским интерфейсом. Это может означать объекты или модели вашего домена, уровень доступа к данным, уровень обслуживания и т. Д. Все эти компоненты хранятся отдельно от пользовательского интерфейса. Они являются частями головоломки, которые делают ваше приложение важным для пользователей.

Мечты о WORA начинают рушиться, когда вы начинаете смотреть на косметические аспекты вашего приложения. На этом этапе вы начинаете работать с разными SDK с разными способами описания элементов пользовательского интерфейса. Кнопка больше не просто кнопка. Кнопка теперь является объектом Button описанным с использованием XAML и C # (среди других возможных языков) в Windows Phone. Кнопка — это объект Button описанный в AXML и Java на Android. Кнопка — это экземпляр UIButton описанный в собственном формате XML и Objective-C на iOS.

Учитывая инструменты, которыми вы располагаете, лучшее, что вы можете сделать, — это создать отделение этих компонентов пользовательского интерфейса от вашего функционального кода. Все это начинает меняться с появлением Xamarin.Forms в недавнем выпуске Xamarin 3 , но мы рассмотрим это в другом учебнике.

Если вы хотите создать кроссплатформенное приложение в экосистеме Xamarin , вы обычно будете использовать формулу создания по крайней мере n + 1 проектов для каждого приложения, ориентированного на n платформ. Почему хотя бы? Почему n + 1? N + 1 является легкой частью. Общепринятый способ — разделить ваше приложение на отдельные проекты, например:

  • App.Core
  • App.iOS (проект Xamarin.iOS)
  • App.Android (проект Xamarin.Android)

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

По крайней мере, часть больше личного предпочтения. В зависимости от того, как вам обычно нравится разбивать код, третий проект (Core) может быть либо одной библиотекой классов, либо несколькими. Это полностью зависит от вас. Вот где вы можете напрячь свои творческие мышцы. Но это не так просто, как создание нового проекта библиотеки классов и создание кода. Если бы это было так просто, все бы так делали. К счастью, у вас есть несколько опробованных и верных вариантов для обмена этим кодом.

Если вы хотите написать код на C # и поделиться им на нескольких платформах в проекте Xamarin , у вас есть три основных варианта:

  • Связывание файлов
  • Портативные библиотеки классов
  • Совместные проекты

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

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

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

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

Для этого примера назовите ваш первый проект SourceLibrary . Внутри этой библиотеки классов создайте новый класс и назовите его User . Замените реализацию класса следующим:

1
2
3
4
5
public class User
{
    public string FirstName { get;
    public string LastName { get;
}

Теперь у вас есть базовый класс, который представляет User в вашем приложении. Если вы хотите поделиться этой концепцией с другим проектом в вашем решении, вы можете добавить ссылку . Во-первых, вам нужно создать новый проект библиотеки классов в вашем решении. Давайте назовем этот LinkLibrary . После создания проекта вы можете добавить ссылку в свой класс User , щелкнув правой кнопкой мыши ваш проект LinkLibrary и выбрав « Добавить файлы в Xamarin Studio» или « Добавить существующие файлы в Visual Studio». Перейдите к файлу, на который вы хотите сослаться, в диалоговом окне « Открыть файл ». Когда вы нажмете кнопку « Открыть» в Xamarin Studio, вы увидите диалоговое окно, которое выглядит следующим образом:

Чтобы добавить ссылку, выберите последний вариант, добавьте ссылку на файл и нажмите « ОК» . Вы успешно создали ссылку на оригинальный файл.

В Visual Studio, когда вы найдете файл, на который вы хотите сослаться, в диалоговом окне « Открыть файл », вы заметите небольшое выпадающее меню с правой стороны кнопки « Добавить» . Если вы щелкнете по этому меню, вам будет предложено несколько вариантов:

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

После нажатия кнопки « Добавить как ссылку» Visual Studio создаст ссылку на файл User в проекте LinkLibrary . Создав ссылку на файл, вы увидите этот связанный файл в текущем решении со странным значком в углу, чтобы указать, что это связанный файл.

Теперь отредактируйте класс User в своем проекте LinkLibrary, чтобы он выглядел следующим образом.

1
2
3
4
5
6
public class User
{
    public string FirstName { get;
    public string LastName { get;
    public string UserName { get;
}

После сохранения изменений и возврата к User класс в вашем проекте SourceLibrary , вы должны увидеть, что обе версии изменились.

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

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

Портативные библиотеки классов или PCL — это следующая эволюция в создании кроссплатформенного кода в мире .NET. PCL — это урезанные версии проектов библиотек классов, которые содержат только базовые функциональные возможности, на которые можно ссылаться и выполнять без изменений в нескольких различных типах проектов. Список поддерживаемых платформ и функций продолжает расти. Чтобы получить более подробную информацию о PCL и увидеть поддерживаемые платформы и функции, взгляните на страницу Portable Class Library в MSDN .

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

Начните с создания нового проекта в Xamarin Studio или Visual Studio, выберите Class Library в качестве шаблона проекта и назовите проект TypicalLibrary . Затем добавьте новый проект в ваше решение. Выберите Class Library (Portable) в качестве шаблона и назовите его PortableLibrary . В зависимости от вашей IDE этот процесс может немного отличаться.

Если вы создадите свой новый проект Portable Class Library в Visual Studio, появится диалоговое окно, подобное приведенному ниже.

В зависимости от установленной версии Visual Studio, .NET Framework и инструментов Xamarin могут отображаться разные варианты, но концепции совпадают. Вы можете выбрать различные платформы, которые хотите поддерживать. Комбинации платформ, которые вы выбираете здесь, ограничены только вашим воображением. Только не забудьте выбрать только те платформы, которые вам нужны. Чем больше платформ вы выберете, тем более ограниченным будет набор функций, доступных для вашего PCL.

Если вы используете Xamarin Studio, вы не увидите диалоговое окно выше. Xamarin Studio по умолчанию установит для вас аналогичные параметры. Чтобы изменить поддерживаемые платформы, щелкните правой кнопкой мыши проект PortableLibrary и выберите « Параметры» . В диалоговом окне параметров проекта выберите « Общие» в разделе « Сборка ». Вы должны увидеть набор опций, похожих на показанные ниже.

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

Наконец, добавьте еще один проект в ваше решение. Выберите шаблон приложения Android и назовите проект BasicAndroidApplication . Чтобы использовать функциональность, созданную в библиотеке классов, добавьте ссылку на нее из приложения Android. Если вы используете Xamarin Studio, вы можете сделать это, щелкнув правой кнопкой мыши папку References под вашим проектом BasicAndroidApplication и выбрав Edit References . В диалоговом окне « Редактирование ссылок » выберите вкладку « Проекты » для ссылки на сборку в текущем решении. Вот что вы увидите:

Вы можете выбрать PCL ( PortableLibrary ), но, как видите, обычная библиотека классов ( TypicalLibrary ) несовместима.

Попытка выполнить это упражнение в Visual Studio в конечном итоге закончится в том же месте, но Visual Studio станет немного менее очевидным. Это позволит вам добавить ссылку на обычную библиотеку классов, но в разделе Ссылки BasicAndroidApplication вы увидите TypicalLibrary со значком предупреждения.

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

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

При использовании PCL в вашем решении очень мало различий с использованием обычных библиотек классов. Во время разработки, когда вы хотите использовать какие-либо классы, определенные в вашем PCL, вы просто добавляете ссылку на него и все готово. В процессе сборки вывод PCL является   Файл DLL, как и обычная библиотека классов.

Когда вы создаете и ссылаетесь на PCL в своем проекте, это физическое   Файл DLL включен в приложение, поэтому основная сборка приложения всегда имеет к нему доступ. Это может вас не удивить, но это отличительная черта при сравнении его с третьим вариантом, который мы сейчас обсудим.

Общие проекты и поддержка их соответствующих шаблонов проектов были добавлены в Xamarin Studio 5 и Visual Studio 2013 Update 2. Хотя название довольно скромное, эти проекты работают совсем не так, как их библиотеки классов и родственники PCL. Эти проекты не имеют ограничений, которые есть у PCL. Они имеют полный доступ к встроенным библиотекам и сборкам в .NET Framework, за исключением того, что вы не можете добавлять дополнительные ссылки и компоненты в эти проекты.

Начните с создания нового решения / проекта в Xamarin Studio или Visual Studio. Выберите C # в качестве языка и выберите шаблон Shared Project . Если вы используете Visual Studio и не видите это как вариант, то вам нужно скачать и установить расширение Shared Project Reference Manager . После завершения установки и перезапуска Visual Studio вы должны увидеть эту опцию.

После создания проекта вы заметите, что он немного пустой. Нет папок Ресурсы или Компоненты . Не создано ни свойств, ни классов по умолчанию. Вы просто получаете чистый лист.

Вы также заметите, что свойств становится меньше, если щелкнуть правой кнопкой мыши по проекту и выбрать « Свойства» в контекстном меню.

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

Одним из важных аспектов Shared Projects является их поддержка директив компилятора. Это одна из причин, по которой они так хорошо вписываются в кроссплатформенные проекты. Существует ряд директив, которые включены в проекты Xamarin и Windows Phone.

  • __MOBILE__ , определенный в проектах Xamarin.iOS и Xamarin.Android
  • __IOS__ , определенный в проектах Xamarin.iOS
  • __ANDROID__ , определенный в проектах Xamarin.Android
  • WINDOWS_PHONE , определенный в проектах Windows Phone
  • SILVERLIGHT , определенный в проектах Windows Phone

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

1
2
3
4
5
6
7
8
public class User
{
#if __ANDROID__
    public string FirstName { get;
#endif
 
    public string LastName { get;
}

Это может быть немного надуманным примером, но он служит цели. Когда компилятор обнаружит этот блок кода в проекте Xamarin.Android, класс User будет иметь свойства FirstName и LastName . Если бы вы строили это в проекте Xamarin.iOS, класс User содержал бы только свойство LastName .

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

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

Что произойдет, если в вашем решении есть общий проект, на который не ссылаются другие проекты? Ничего. Код не компилируется и впоследствии нигде не включается. То же самое произойдет, если вы добавите ссылку на проект Xamarin.iOS, который указывает на общий проект, который содержит класс User выше. Поскольку директива __ANDROID__ не определена в Xamarin.iOS, свойство FirstName не будет скомпилировано в проект Xamarin.iOS.

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

Связывание файлов — это процесс создания логических ссылок из одного проекта на физический файл в другом проекте или каталоге.

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

PCL — это специализированный проект библиотеки классов, который можно включать и запускать на нескольких разных платформах без изменений.

  • генерирует сборку, на которую могут ссылаться другие проекты
  • все рефакторинг и тестирование могут быть выполнены в одном месте
  • не может ссылаться на какие-либо сборки, не относящиеся к PCL или платформе
  • включает только подмножество функций .NET Framework

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

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

С развитием Xamarin и внедрением стратегии Shared Project, опция « Связывание файлов» практически упала на второй план. Это не означает, что вы не можете или не должны использовать эту опцию, это просто означает, что в большинстве случаев лучше всего подходят стратегии Portable Class Library или Shared Project . Вот простые сценарии для определения того, с кем идти.

  • Portable Class Library , создающая кроссплатформенное приложение, в котором общий код не зависит от платформы и предназначен для совместного использования или повторного использования вне текущего решения
  • Shared Project , создающий кроссплатформенное приложение с кодом, который может быть специфичным для платформы и принадлежать только вашему решению и не предназначен для совместного использования или повторного использования вне этого контекста

Этого достаточно для теории. Давайте напишем некоторый код. В двух предыдущих вводных уроках по Xamarin вы создали одну и ту же программу чтения RSS. Хотя в то время это могло показаться излишним, мы сделали это по двум причинам.

  1. показать сходство в создании приложений Xamarin.iOS и Xamarin.Android
  2. привести к объединению общего кода в одном кроссплатформенном приложении

Чтобы создать эту версию своего приложения, вы будете следовать основным принципам n + 1 . Начните с создания нового проекта iOS с использованием шаблона Empty Project , назвав проект XamFeed.iOS и решение XamFeed .

Затем добавьте новый проект Android в свое решение, используя шаблон проекта приложения Android . Назовите новый проект XamFeed.Android .

Теперь пришло время +1 . Вы можете выбрать любой из вариантов совместного использования кода, описанных в этом руководстве, чтобы создать это приложение. Поскольку код, предназначенный для совместного использования приложениями iOS и Android, не является специфичным для какой-либо одной платформы и может быть полезен для других проектов и приложений, я выберу версию Portable Class Library . Добавьте новый проект C # в свое решение с помощью шаблона Portable Library и назовите его XamFeed.Core .

Если вы используете Visual Studio, вы увидите диалоговое окно, в котором можно выбрать поддерживаемые платформы. Если вы используете Xamarin Studio, вам нужно просмотреть свойства проекта для проекта XamFeed.Core . Вы можете выбрать практически любую комбинацию платформ, если вы используете .NET Framework 4.5 или более позднюю версию , Xamarin.iOS и Xamarin.Android , и убедитесь, что не выбрали Windows Phone 8 и Windows Phone Silverlight 8 . Причина, по которой вы не можете выбрать эти две платформы, заключается в том, что они не поддерживают Класс HttpClient который мы будем использовать в нашем приложении.

Вы можете удалить файл класса по умолчанию в библиотеке XamFeed.Core , потому что он нам не понадобится. Наконец, обязательно добавьте ссылку на проект XamFeed.Core в обоих проектах XamFeed.iOS и XamFeed.Android . Теперь вы готовы добавить код.

Начнем с создания объекта домена RssItem . Этот класс будет содержать четыре свойства. Вы можете добавить больше, если хотите.

  • Title , название статьи
  • PubDate , дата публикации статьи
  • Creator , автор статьи
  • Link , URL статьи

Добавьте новый класс в ваш проект RssItem именем RssItem . Замените реализацию по умолчанию следующим:

1
2
3
4
5
6
7
public class RssItem
{
    public string Title { get;
    public string PubDate { get;
    public string Creator { get;
    public string Link { get;
}

Создайте другой класс и назовите его FeedRetriever . Задача этого класса будет получать массив объектов RssItem по заданному URL. Создав этот класс, добавьте в него новый метод со следующей реализацией:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public async Task<RssItem[]> GetItems(string feedUrl)
{
    using (var client = new HttpClient())
    {
        var xmlFeed = await client.GetStringAsync(feedUrl);
        var doc = XDocument.Parse(xmlFeed);
        XNamespace dc = «http://purl.org/dc/elements/1.1/»;
 
        var items = (from item in doc.Descendants(«item»)
            select new RssItem
            {
                Title = item.Element(«title»).Value,
                PubDate = item.Element(«pubDate»).Value,
                Creator = item.Element(dc + «creator»).Value,
                Link = item.Element(«link»).Value
            }).ToArray();
 
        return items;
    }
}

Чтобы этот метод компилировался в ваш проект, вам нужно добавить четыре оператора using в начало файла FeedRetriever :

  • using System.Linq;
  • using System.Net.Http;
  • using System.Xml.Linq;
  • using System.Threading.Tasks;

Теперь у вас есть удобный маленький класс, который можно использовать для извлечения статей из заданного URL-адреса RSS-канала. Эта функциональность будет добавлена ​​в приложения для iOS и Android. Начнем с приложения для Android.

Для помещения объектов RssItem в список требуется специальный адаптер. В проекте XamFeed.Android создайте новый класс, назовите его FeedAdapter и замените его реализацию следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class FeedAdapter : BaseAdapter<RssItem>
{
    private RssItem[] _items;
    private Activity _context;
  
    public FeedAdapter( Activity context, RssItem[] items) : base()
    {
        _context = context;
        _items = items;
    }
  
    public override RssItem this[int position]
    {
        get { return _items[position];
    }
  
    public override int Count
    {
        get { return _items.Count();
    }
  
    public override long GetItemId(int position)
    {
        return position;
    }
  
    public override View GetView(int position, View convertView, ViewGroup parent)
    {
        var view = convertView;
        if (view == null)
        {
            view = _context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem2, null);
        }
  
        view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = _items[position].Title;
        view.FindViewById<TextView>(Android.Resource.Id.Text2).Text = string.Format(«{0} on {1}», _items[position].Creator, _items[position].PubDate);
  
        return view;
    }
}

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

  • using Android.Widget;
  • using XamFeed.Core;
  • using Android.App;
  • using Android.Views;
  • using Android.OS;
  • using System.Linq;

Теперь у вас есть механизм для извлечения объектов RssItem и Adapter для их отображения. Все, что вам нужно, это ListView . Замените содержимое Main.axml ( Resources> layout ) следующим:

01
02
03
04
05
06
07
08
09
10
<?xml version=»1.0″ encoding=»utf-8″?>
<LinearLayout xmlns:android=»http://schemas.android.com/apk/res/android»
    android:orientation=»vertical»
    android:layout_width=»fill_parent»
    android:layout_height=»fill_parent»>
    <ListView
        android:id=»@+id/TutsFeedListView»
        android:layout_width=»fill_parent»
        android:layout_height=»fill_parent» />
</LinearLayout>

Приведенная выше схема добавляет ListView к экрану, поэтому вы можете заполнить его данными. Нам остается только MainActivity класс MainActivity к макету, заполнить список объектами RssItem , открыть каждую из ссылок, когда пользователь RssItem одного из элементов. Для этого вам нужно только изменить содержимое MainActivity.cs, как показано ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[Activity(Label = «XamFeed», MainLauncher = true, Icon = «@drawable/icon»)]
public class FeedActivity : ListActivity
{
    private FeedRetriever _retriever;
    private RssItem[] _items;
 
    protected async override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        _retriever = new FeedRetriever ();
 
        _items = await _retriever.GetItems («http://blog.xamarin.com/feed»);
 
        ListAdapter = new FeedAdapter (this, _items);
 
    }
 
    protected override void OnListItemClick(ListView l, View v, int position, long id)
    {
        base.OnListItemClick(l, v, position, id);
        var uri = global::Android.Net.Uri.Parse (_items [position].Link);
 
        var intent = new Intent (Intent.ActionView, uri);
        StartActivity(intent);
    }
}

Вам нужно будет добавить оператор using для включения пространства имен XamFeed.Core чтобы компилировать его.

Там у вас есть это. Теперь у вас есть полнофункциональное приложение для Android, которое использует основные функции, которые находятся в Portable Class Library . Теперь пришло время обратить наше внимание на проект XamFeed.iOS .

Основной процесс запуска и запуска проекта iOS будет похож на проект Android. Мы будем использовать класс FeedRetriever для получения объектов RssItem а затем напишем код пользовательского интерфейса, чтобы отобразить его пользователю. Для этого мы создадим контроллер представления, содержащий список объектов RssItem и установим этот контроллер представления в качестве корневого контроллера представления приложения.

Начните с добавления нового контроллера табличного представления iOS в проект XamFeed.iOS и назовите его RssItemView . Это приводит к созданию RssItemViewController , RssItemViewSource и RssItemViewCell .

Эти классы составляют табличное представление, в котором будут отображаться объекты RssItem . Замените реализацию по RssItemViewController класса RssItemViewController следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class RssItemViewController : UITableViewController
{
    private FeedRetriever _retriever;
    private RssItem[] _items;
    public RssItemViewController () : base ()
    {
        _retriever = new FeedRetriever ();
    }
 
    public override void DidReceiveMemoryWarning ()
    {
        // Releases the view if it doesn’t have a superview.
        base.DidReceiveMemoryWarning ();
 
        // Release any cached data, images, etc that aren’t in use.
    }
 
    public async override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
        _items = await _retriever.GetItems («http://blog.xamarin.com/feed»);
        // Register the TableView’s data source
        TableView.Source = new RssItemViewSource (_items);
        TableView.ReloadData ();
 
    }
}

В ViewDidLoad мы используем класс FeedRetriever чтобы получить объекты RssItem из блога Xamarin , назначить их объекту RssItemViewSource и вызвать метод ReloadData для экземпляра TableView . Этот метод обеспечивает обновление табличного представления после его отображения, чтобы данные отображались на экране.

Затем обновите класс RssItemViewSource для обработки RssItem[] который мы ему передаем. Для этого замените реализацию по умолчанию на следующую:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class RssItemViewSource : UITableViewSource
{
    private RssItem[] _items;
 
    public RssItemViewSource (RssItem[] items)
    {
        _items = items;
    }
 
    public override int NumberOfSections (UITableView tableView)
    {
        // TODO: return the actual number of sections
        return 1;
    }
 
    public override int RowsInSection (UITableView tableview, int section)
    {
        // TODO: return the actual number of items in the section
        return _items.Length;
    }
 
    public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
    {
        var cell = tableView.DequeueReusableCell (RssItemViewCell.Key) as RssItemViewCell;
        if (cell == null)
            cell = new RssItemViewCell ();
 
        // TODO: populate the cell with the appropriate data based on the indexPath
 
        cell.TextLabel.Text = _items[indexPath.Row].Title;
        cell.DetailTextLabel.Text = string.Format («{0} on {1}», _items [indexPath.Row].Creator, _items [indexPath.Row].PubDate);
 
        return cell;
    }
 
    public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
    {
        var item = _items [indexPath.Row];
 
        var url = new NSUrl (item.Link);
        UIApplication.SharedApplication.OpenUrl (url);
    }
}

Большая часть работы здесь выполняется в методе GetCell . Здесь мы либо создаем новую ячейку, если она не существует, либо повторно используем ячейку, которая вышла из поля зрения. Получив ячейку, мы заполняем ее свойствами Title , Creator и PubDate соответствующего объекта RssItem .

Наконец, нам нужно определить внешний вид ячеек в UITableView . Для этого мы используем класс RssItemViewCell . Замените реализацию по умолчанию следующим:

01
02
03
04
05
06
07
08
09
10
public class RssItemViewCell : UITableViewCell
{
    public static readonly NSString Key = new NSString («FeedItemViewControllerCell»);
 
    public RssItemViewCell () : base (UITableViewCellStyle.Subtitle, Key)
    {
        // TODO: add subviews to the ContentView, set various colors, etc.
        TextLabel.Text = «TextLabel»;
    }
}

Вы, возможно, заметили, что это выглядит почти так же, как реализация по умолчанию, только с одним незначительным изменением, мы передаем UITableViewCell.Subtitle в base конструктор. Это дает каждой ячейке два текстовых поля, которые вы можете заполнить.

Теперь у нас есть все, что нужно, чтобы показать список объектов RssItem пользователю. Есть только одна проблема. Мы не добавили представление контроллера представления в иерархию представления нашего приложения. Это легко исправить, хотя. Обновите метод FinishedLaunching в классе AppDelegate как показано ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
    // create a new window instance based on the screen size
    window = new UIWindow (UIScreen.MainScreen.Bounds);
    var controller = new RssItemViewController ();
    controller.View.BackgroundColor = UIColor.White;
    controller.Title = «Xamarin Feeds»;
 
    var navController = new UINavigationController (controller);
    window.RootViewController = navController;
    // If you have defined a root view controller, set it here:
    // window.RootViewController = myViewController;
     
    // make the window visible
    window.MakeKeyAndVisible ();
     
    return true;
}

Сначала мы создаем новый экземпляр RssItemViewController и устанавливаем пару его свойств. Затем мы создаем новый экземпляр UINavigationViewController , передавая ему контроллер представления, который мы создали минуту назад. Наконец, мы устанавливаем новый контроллер навигации как RootViewController экземпляра UIWindow . Вот и все.

Теперь у нас есть приложение для Android и iOS, которое отображает RSS-канал блога Xamarin. Вы можете запускать эти приложения по одному и видеть, как они работают по отдельности, или вы можете запускать их оба в одном сеансе отладки. Для этого вам просто нужно перейти к свойствам или параметрам решения XamFeed , в зависимости от вашей IDE. Здесь вы можете выбрать, какие проекты вы хотите запустить при запуске приложения. В своем решении выберите XamFeed.Android и XamFeed.iOS .

Сохраните изменения и теперь, когда вы запустите приложение, iOS Simulator и Android Emulator запустят и запустят ваше приложение.

Поздравляю. Вы успешно создали кроссплатформенное мобильное приложение с единой кодовой базой. Важно понимать, что создание этих приложений не обязательно совпадает с мышлением « Write Once Run Anywhere» . Там всегда будет необходимость настройки. К счастью, благодаря комбинации Xamarin и некоторых очень классных стратегий совместного использования кода, вы можете быть очень близки. Если вы просто начинаете думать о своих мобильных приложениях с точки зрения кода, специфичного для платформы, и кода, не зависящего от платформы, то вы уже на своем пути.

Если вы хотите узнать больше о Xamarin, ознакомьтесь с нашим курсом Создание многоплатформенных приложений на C # в Xamarin .

В ходе курса вы узнаете, как создать кроссплатформенное приложение из единой кодовой базы, которая будет работать на трех совершенно разных платформах: iOS, Android и Windows Phone 8. Думаешь, это невозможно? Через некоторое время вы будете делать это самостоятельно. Давай приступим к работе.

Вы можете воспользоваться бесплатной 14-дневной пробной версией подписки Tuts +. Для начала ознакомьтесь с нашими вариантами подписки или, если вы заинтересованы в этом курсе, вы можете приобрести его отдельно за 15 долларов! Вот предварительный просмотр, чтобы вы начали: