Сохранение бабушкиных рецептов с помощью Xamarin.Forms
Опубликовано: 2022-03-10Моя бабушка делает самые вкусные, самые пышные булочки, от которых невозможно оторвать колени, которые кто-либо когда-либо пробовал. Проблема в том, что есть масса секретных ингредиентов (и я не просто говорю о любви), которые входят в эти булочки, и все эти ингредиенты и рецепты хранятся в голове моей бабушки.
У всех нас есть такие семейные рецепты, и вместо того, чтобы, возможно, забыть о них, в этой статье мы собираемся создать мобильное приложение для iOS и Android с помощью Xamarin.Forms, которое сохранит их для меня и будущих поколений моей семьи!
Так что, если вы заинтересованы в написании мобильных приложений, но у вас нет времени писать одно и то же приложение снова и снова для каждой платформы, эта статья для вас! Не волнуйтесь, если вы не знаете C# из клубничного салата с крендельками; Я пишу приложения Xamarin более 8 лет, и эта статья представляет собой экскурсию по Xamarin.Forms, цель которой — предоставить вам достаточно информации, чтобы начать учиться самостоятельно.
Что это за материал Xamarin?
Xamarin позволяет разработчикам создавать нативные приложения для iOS и Android, используя те же SDK и элементы управления пользовательского интерфейса, что и в Swift и XCode для iOS или Java и Android Studio для Android.
Разница в том, что приложения разрабатываются на C# с использованием .NET Framework и Visual Studio или Visual Studio для Mac. Однако приложения, которые в результате получаются, точно такие же. Они выглядят, работают и ведут себя точно так же, как нативные приложения, написанные на Objective-C, Swift или Java.
Xamarin сияет, когда дело доходит до совместного использования кода. Разработчик может создать и адаптировать свой пользовательский интерфейс для каждой платформы, используя собственные элементы управления и SDK, а затем написать библиотеку общей логики приложения, которая используется на разных платформах.
Именно такое совместное использование кода позволяет добиться огромной экономии времени.
И, подобно вкусным булочкам, которые печет моя бабушка, однажды попробовав поделиться кодом — трудно не желать большего — и вот здесь на помощь приходит Xamarin.Forms.
Xamarin.Формы
Xamarin.Forms использует концепцию традиционной разработки Xamarin и добавляет к ней уровень абстракции.
Вместо того, чтобы разрабатывать пользовательский интерфейс для iOS и Android отдельно, Xamarin.Forms представляет набор инструментов пользовательского интерфейса, который позволяет писать собственные мобильные приложения из единой базы кода.
Подумайте об этом так: у вас есть приложение, которому нужна кнопка. Каждая платформа имеет концепцию кнопки. Зачем вам писать пользовательский интерфейс кучу раз, когда вы знаете, что все, что нужно сделать пользователю вашего приложения, это нажать кнопку?
Это одна из проблем, которую решает Xamarin.Forms.
Он предоставляет набор наиболее часто используемых элементов управления и событий взаимодействия с пользователем для них, поэтому нам нужно только один раз написать пользовательские интерфейсы для наших приложений. Однако стоит отметить, что вы не ограничены элементами управления, предоставляемыми Xamarin.Forms, — вы по-прежнему можете использовать элементы управления, имеющиеся только на одной платформе, в приложении Xamarin.Forms. Кроме того, мы можем разделить логику приложения между платформами, как и раньше.
Статистика совместного использования кода для приложений, разработанных с помощью Xamarin.Forms, может быть запредельной. Приложение для организации конференций имеет 93% общего кода на iOS и 91% на Android. Приложение с открытым исходным кодом. Взгляните на код.
Xamarin.Forms предоставляет не только элементы управления пользовательского интерфейса. Он также содержит структуру MVVM, службу обмена сообщениями pub/sub, API анимации и службу зависимостей, а также многое другое.
Но сегодня мы сосредоточимся на возможностях пользовательского интерфейса для создания нашего приложения для управления рецептами.
Приложение, которое мы создадим
Приложение менеджера рецептов будет иметь простой пользовательский интерфейс. Мы будем работать на кухне, поэтому им должно быть легко пользоваться!
Он будет состоять из 3-х экранов . Первый покажет список всех рецептов, загруженных в данный момент в приложение.
Затем, нажав на один из этих рецептов, вы сможете увидеть его детали на втором экране:
Оттуда вы можете нажать кнопку редактирования, чтобы внести изменения в рецепт на третьем экране:
Вы также можете попасть на этот экран, нажав кнопку добавления на экране списка рецептов.
Среда разработки
Приложения Xamarin создаются с помощью C# и .NET с использованием Visual Studio для Windows или Visual Studio для Mac для Mac, но вам также необходимо установить пакеты SDK и инструменты для iOS или Android. Установка всего в правильном порядке может быть проблемой, однако установщики Visual Studio позаботятся об установке не только IDE, но и инструментов платформы.
Хотя для создания приложений iOS всегда требуется компьютер Mac, с помощью Xamarin вы по-прежнему можете разрабатывать и отлаживать эти приложения из Visual Studio для Windows! Так что, если вам больше всего нравится Windows, нет необходимости полностью менять среду.
Теперь давайте посмотрим, как Xamarin.Forms может помочь нам сохранить некоторые семейные рецепты из одной базы кода!
Страница списка рецептов: макет пользовательского интерфейса
Давайте начнем с разговора о том, как мы собираемся настроить пользовательский интерфейс для нашего приложения для сохранения рецептов!
В целом каждый экран в Xamarin.Forms состоит из 3 элементов. Page
. По крайней мере, один элемент с именем Layout
. И хотя бы один Control
.
Страница
Страница — это то, что одновременно содержит все, что отображается на экране. Page
также занимает центральное место в навигации внутри приложения.
Мы сообщаем Xamarin.Forms, какую Page
нужно отображать с помощью службы навигации . Затем эта служба позаботится об отображении любой страницы способом, подходящим и родным для операционной системы.
Другими словами, код для навигации между экранами тоже был абстрагирован!
Наконец, хотя это и не единственный способ сделать это, я кодирую пользовательский интерфейс моей Page
в XAML. (Другой способ — использовать C#.) XAML — это язык разметки, описывающий внешний вид страницы. А пока достаточно сказать, что это чем-то похоже на HTML.
Расположение
Все элементы управления на странице организованы с помощью чего-то, что называется макетом.
На страницу можно добавить один или несколько макетов.
Существует несколько различных типов макетов в формах. Некоторые из наиболее распространенных включают макеты Stack, Absolute, Relative, Grid, Scroll и Flex.
Элементы управления
Наконец, есть элементы управления. Это виджеты вашего приложения, с которыми взаимодействует пользователь.
Формы поставляются со многими элементами управления, которые будут использоваться независимо от того, какой тип приложения вы создаете. Такие вещи, как метки, кнопки, поля ввода, изображения и, конечно же, списки.
При добавлении элемента управления на экран вы добавляете его в макет. Именно макет определяет, где именно на экране должен появиться элемент управления.
Итак, для создания следующих экранов на iOS и Android соответственно:
Я использовал этот XAML:
<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="https://xamarin.com/schemas/2014/forms" xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml" x:Class="SmashingRecipe.RecipeListPage" Title="Recipes"> <ContentPage.Content> <StackLayout> <ListView x:Name="recipesList"> <ListView.ItemTemplate> <DataTemplate> <TextCell Text="{Binding Name}"/> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage.Content> <ContentPage.ToolbarItems> <ToolbarItem Text="Add" /> </ContentPage.ToolbarItems> </ContentPage>
Здесь происходит несколько важных вещей.
Первый — это <StackLayout>
. Это говорит Forms расположить все элементы управления, которые следуют в стеке.
В макете есть только один элемент управления, и это <ListView>
, и мы собираемся дать ему имя, чтобы мы могли сослаться на него позже.
Затем немного шаблонной церемонии для ListView
, прежде чем мы доберемся до того, что нам нужно: <TextCell>
. Это говорит формам отображать простой текст в каждой ячейке списка.
Мы <TextCell>
текст, который мы хотим, чтобы он отображал, с помощью метода, называемого привязкой данных . Синтаксис выглядит как Text="{Binding Name}"
. Где Name
— это свойство класса Recipe
, которое моделирует… Ну, Recipes.
Так как же рецепты добавляются в список?
Наряду с каждым файлом XAML существует файл кода программной части. Этот программный код позволяет нам выполнять такие действия, как обработка событий взаимодействия с пользователем, выполнение настройки или выполнение другой логики приложения.
На каждой Page
есть OnAppearing
, которую можно переопределить. Она, как вы, наверное, догадались, вызывается при появлении Page
.
protected override void OnAppearing() { base.OnAppearing(); recipesList.ItemsSource = null; recipesList.ItemsSource = App.AllRecipes; }
Обратите внимание на recipesList.ItemsSource = AllRecipes;
Это говорит ListView
— «Эй! Все ваши данные находятся в перечислимом App.AllRecipes
(переменная для всего приложения), и вы можете использовать любое из свойств его дочернего объекта для привязки!».
Список рецептов — это хорошо, но вы не можете ничего испечь, не ознакомившись с деталями рецепта, — и мы позаботимся об этом позже.
Обработка событий
Не реагируя на прикосновения пользователя, наше приложение представляет собой не что иное, как список аппетитно звучащих рецептов. Звучат хорошо, но без умения их готовить толку мало!
Давайте сделаем так, чтобы каждая ячейка в ListView
реагировала на нажатия, чтобы мы могли увидеть, как приготовить рецепт!
В файле кода программной части RecipeListPage
мы можем добавить обработчики событий к элементам управления, чтобы прослушивать и реагировать на события взаимодействия с пользователем.
Обработка событий касания в представлении списка, а затем:
recipesList.ItemSelected += async (sender, eventArgs) => { if (eventArgs.SelectedItem != null) { var detailPage = new RecipeDetailPage(eventArgs.SelectedItem as Recipe); await Navigation.PushAsync(detailPage); recipesList.SelectedItem = null; } };
Там какие-то крутые штуки творятся.
Всякий раз, когда кто-то выбирает строку, ItemSelected
запускается в ListView
.
Из аргументов, которые передаются обработчику, объект eventArgs
имеет свойство SelectedItem
, которое оказывается тем, что ранее было привязано к ListView
.
В нашем случае это класс Recipe
. (Поэтому нам не нужно искать объект в главном источнике — он передается нам.)
Страница сведений о рецепте
Конечно, есть страница, которая показывает нам секретные ингредиенты и инструкции по приготовлению каждого рецепта, но как эта страница отображается?
Обратите внимание на await Navigation.PushAsync(detailPage);
линия сверху. Объект Navigation
— это независимый от платформы объект, который обрабатывает переходы страниц собственным способом для каждой платформы.
Теперь давайте взглянем на страницу сведений о рецепте:
Эта страница также построена с помощью XAML. Однако используемый Layout
(FlexLayout) довольно крут, поскольку он вдохновлен CSS Flexbox.
<ContentPage.Content> <ScrollView> <FlexLayout AlignItems="Start" AlignContent="Start" Wrap="Wrap"> <Image Source="buns.png" FlexLayout.Basis="100%" /> <Label Text="{Binding Name}" HorizontalTextAlignment="Center" TextColor="#01487E" FontAttributes="Bold" FontSize="Large" Margin="10, 10" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="Ingredients" FontAttributes="Bold" FontSize="Medium" TextColor="#EE3F60" Margin="10,10" HorizontalOptions="FillAndExpand" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="{Binding Ingredients}" Margin="10,10" FontSize="Small" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="Directions" FontAttributes="Bold" FontSize="Medium" TextColor="#EE3F60" Margin="10,10" HorizontalOptions="FillAndExpand" /> <BoxView FlexLayout.Basis="100%" HeightRequest="0" /> <Label Text="{Binding Directions}" Margin="10,10" FontSize="Small" /> </FlexLayout> </ScrollView> </ContentPage.Content>
FlexLayout
расположит свои элементы управления в строках или столбцах. Однако большое преимущество заключается в том, что он может автоматически определять, сколько места на экране осталось для размещения элемента управления, и, если его недостаточно, он может автоматически создать новую строку или столбец для его размещения!
Это очень помогает при работе с экранами разных размеров, которых в мобильной разработке предостаточно.
Что ж, с FlexLayout
, помогающим нам поддерживать внешний вид экрана с подробностями, нам все еще нужно редактировать эти рецепты, верно?
Вы, наверное, заметили это:
<ToolbarItem Text="Edit" Clicked="Edit_Clicked" />
Эта строка отвечает за размещение кнопки на панели инструментов приложения. Clicked="Edit_Clicked"
сообщает кнопке, что при ее нажатии следует искать в коде функцию с таким именем, а затем выполнять ее код.
В данном случае это будет создание экземпляра страницы редактирования рецепта и добавление ее в наш стек навигации с помощью объекта Navigation
, упомянутого ранее.
Страница редактирования рецепта
Страница со списком рецептов: проверить! Страница со всеми подробностями для приготовления рецептов: проверьте! Осталось только создать страницу, которую мы используем для ввода или изменения рецепта, пока мы наблюдаем, как бабушка творит свое волшебство!
Во-первых, проверьте экраны:
А теперь код:
<ContentPage.Content> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <TableView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Intent="Form" HasUnevenRows="true"> <TableSection Title="General"> <EntryCell x:Name="recipeNameCell" Label="Name" /> </TableSection> <TableSection Title="Ingredients"> <ViewCell> <StackLayout Padding="15"> <Editor x:Name="ingredientsCell" /> </StackLayout> </ViewCell> </TableSection> <TableSection Title="Directions"> <ViewCell> <StackLayout Padding="15"> <Editor x:Name="directionsCell" /> </StackLayout> </ViewCell> </TableSection> </TableView> <Button Text="Save" Grid.Row="1" Grid.Column="0" BackgroundColor="#EE3F60" TextColor="White" x:Name="saveButton" /> <Button Text="Cancel" Grid.Row="1" Grid.Column="1" BackgroundColor="#4CC7F2" TextColor="White" x:Name="cancelButton" /> </Grid> </ContentPage.Content>
Здесь немного больше кода, и это потому, что я использую макет Grid
, чтобы указать, как все должно располагаться в 2-мерном шаблоне.
Также обратите внимание, что здесь нет привязки данных. Потому что я хотел привести пример того, как можно заполнить элементы управления исключительно из кода файла:
void InitializePage() { Title = TheRecipe.Name ?? "New Recipe"; recipeNameCell.Text = TheRecipe.Name; ingredientsCell.Text = TheRecipe.Ingredients; directionsCell.Text = TheRecipe.Directions; saveButton.Clicked += async (sender, args) => { SaveRecipe(); await CloseWindow(); }; cancelButton.Clicked += async (sender, args) => { await CloseWindow(); }; }
Видите это свойство TheRecipe
? Это уровень страницы, он содержит все данные для конкретного рецепта и устанавливается в конструкторе страницы.
Во-вторых, обработчики событий Clicked
для saveButton
и cancelButton
полностью соответствуют .NET (и да, я довольно часто придумываю собственные слова).
Я говорю, что они ориентированы на .NET, потому что синтаксис для обработки этого события не является родным для Java или Objective-C. Когда приложение работает на Android или iOS, поведение будет точно таким же, как у Android Click или iOS TouchUpInside.
И, как вы видите, каждый из этих обработчиков кликов вызывает соответствующие функции, которые либо сохраняют рецепт и закрывают страницу, либо только закрывают страницу.
Вот и все — у нас есть пользовательский интерфейс, позволяющий сохранять рецепты с этого момента и до скончания веков!
CSS Что?!? Или сделать приложение красивым
Оставим лучшее напоследок: Xamarin.Forms 3.0 дает нам, среди прочего, возможность стилизовать элементы управления с помощью CSS!
CSS Xamarin.Forms не на 100 % то, к чему вы, возможно, привыкли в веб-разработке. Но это достаточно близко, чтобы любой, кто знаком с CSS, чувствовал себя как дома. Прямо как я у бабушки!
Итак, давайте возьмем страницу сведений о рецепте и рефакторим ее, чтобы она использовала каскадные таблицы стилей для установки визуальных элементов вместо того, чтобы задавать все непосредственно в XAML.
Первый шаг — создать документ CSS! В этом случае это будет выглядеть следующим образом:
.flexContent { align-items: flex-start; align-content: flex-start; flex-wrap: wrap; } image { flex-basis: 100%; } .spacer { flex-basis: 100%; height: 0; } .foodHeader { font-size: large; font-weight: bold; color: #01487E; margin: 10 10; } .dataLabel { font-size: medium; font-weight: bold; color: #EE3F60; margin: 10 10; } .data { font-size: small; margin: 10 10; }
По большей части это похоже на CSS. Там есть классы. Существует единственный селектор для типа класса Image
. А потом куча установщиков свойств.
Некоторые из этих задатчиков свойств, такие как flex-wrap
или flex-basis
, специфичны для Xamarin.Forms. В дальнейшем команда будет ставить перед именами префикс xf-
, чтобы следовать стандартной практике.
Далее нужно будет применить его к элементам управления XAML.
<ContentPage.Resources> <StyleSheet Source="../Styles/RecipeDetailStyle.css" /> </ContentPage.Resources> <ContentPage.Content> <ScrollView> <FlexLayout StyleClass="flexContent"> <Image Source="buns.png" /> <Label Text="{Binding Name}" StyleClass="foodHeader" /> <BoxView StyleClass="spacer" /> <Label Text="Ingredients" StyleClass="dataLabel" HorizontalOptions="FillAndExpand" /> <BoxView StyleClass="spacer" /> <Label Text="{Binding Ingredients}" StyleClass="data" /> <BoxView StyleClass="spacer" /> <Label Text="Directions" StyleClass="dataLabel" HorizontalOptions="FillAndExpand" /> <BoxView StyleClass="spacer" /> <Label Text="{Binding Directions}" StyleClass="data" /> </FlexLayout> </ScrollView> </ContentPage.Content>
Вот как это выглядело раньше.
В Xamarin.Forms для ссылки на документ CSS добавьте <StyleSheet Source="YOUR DOC PATH" />
. Затем вы можете ссылаться на классы в каждом элементе управления через свойство StyleClass
.
Это определенно очищает XAML, а также делает более понятным назначение элемента управления. Например, теперь совершенно очевидно, что задумали эти <BoxView StyleClass="spacer" />
!
И Image
получает стиль, потому что это Image
и то, как мы определили селектор в CSS.
Безусловно, CSS в Xamarin.Forms реализован не так полно, как его веб-родственник, но все равно довольно круто. У вас есть селекторы, классы, вы можете устанавливать свойства и, конечно же, все эти каскадные штуки!
Резюме
Три экрана, две платформы, одна статья и бесконечные сохраненные рецепты! И вы знаете, что еще? Вы можете создавать приложения с помощью Xamarin.Forms не только для Android и iOS. Вы можете создавать платформы UWP, macOS и даже Samsung Tizen!
Xamarin.Forms — это набор инструментов для создания пользовательского интерфейса, который позволяет создавать приложения, один раз написав пользовательский интерфейс и отобразив его на основных платформах.
Он делает это, предоставляя SDK, который является абстракцией для наиболее часто используемых элементов управления на разных платформах. В дополнение к совершенству пользовательского интерфейса Xamarin.Forms также предоставляет полнофункциональную платформу MVVM, службу обмена сообщениями pub/sub, API анимации и службу зависимостей.
Xamarin.Forms также дает вам те же преимущества кода, что и традиционная разработка Xamarin. Любая логика приложения является общей для всех платформ. И вы можете разрабатывать все свои приложения в одной среде IDE, используя один язык — это круто!
Куда дальше? Загрузите исходный код этого приложения Xamarin.Forms, чтобы попробовать его самостоятельно. Затем, чтобы узнать больше о Xamarin.Forms, в том числе о возможности создания приложения в браузере, ознакомьтесь с этим онлайн-руководством!