Salvarea rețetelor bunicii cu Xamarin.Forms
Publicat: 2022-03-10Bunica mea face cele mai bune, cele mai pufoase, chifle slabe în genunchi pe care oricine le-a gustat vreodată. Problema este că există o mulțime de ingrediente secrete (și nu vorbesc doar de dragoste) care intră în acele chifle, iar acele ingrediente și indicații sunt toate stocate în capul bunicii mele.
Cu toții avem astfel de rețete de familie și, în loc să le uităm, în acest articol vom crea o aplicație mobilă pentru iOS și Android folosind Xamarin.Forms, care le va salva pentru mine și pentru generațiile viitoare ale familiei mele!
Deci, dacă sunteți interesat să scrieți aplicații mobile, dar nu aveți timp să scrieți aceeași aplicație din nou și din nou pentru fiecare platformă, acest articol este pentru dvs.! Nu vă faceți griji dacă nu cunoașteți C# dintr-o salată de covrigi cu căpșuni; Am scris aplicații Xamarin de peste 8 ani, iar acest articol este un tur prin Xamarin.Forms, care intenționează să vă ofere suficiente informații pentru a începe să învățați pe cont propriu.
Ce este acest lucru Xamarin?
Mai mult decât un cuvânt distractiv de spus, Xamarin permite dezvoltatorilor să creeze aplicații native iOS și Android folosind exact aceleași SDK-uri și comenzi UI disponibile ca în Swift și XCode pentru iOS sau Java și Android Studio pentru Android.
Diferența este că aplicațiile sunt dezvoltate cu C# folosind .NET Framework și Visual Studio sau Visual Studio pentru Mac. Aplicațiile care rezultă, totuși, sunt exact aceleași. Ele arată, simt și se comportă la fel ca aplicațiile native scrise în Objective-C, Swift sau Java.
Xamarin strălucește când vine vorba de partajarea codului. Un dezvoltator își poate crea și personaliza interfața de utilizare pentru fiecare platformă folosind controale native și SDK-uri, dar apoi poate scrie o bibliotecă de logica de aplicație partajată care este partajată între platforme.
În acest schimb de cod se pot realiza economii extraordinare de timp.
Și la fel ca chiflele delicioase pe care le coace bunica mea, odată dat fiind gustul de a partaja codul — este greu să nu poftesc mai mult — și aici intervine Xamarin.Forms.
Xamarin.Forms
Xamarin.Forms preia conceptul de dezvoltare tradițională Xamarin și îi adaugă un strat de abstractizare.
În loc să dezvolte separat interfața de utilizator pentru iOS și Android, Xamarin.Forms introduce un set de instrumente UI care vă permite să scrieți aplicații mobile native dintr-o singură bază de cod.
Gândiți-vă la asta astfel: aveți o aplicație care are nevoie de un buton. Fiecare platformă are conceptul unui buton. De ce ar trebui să scrieți interfața cu utilizatorul de mai multe ori când știți că tot ce trebuie să facă utilizatorul aplicației dvs. este să atingă un buton?
Aceasta este una dintre problemele pe care le rezolvă Xamarin.Forms.
Oferă un set de instrumente cu cele mai frecvent utilizate controale și evenimente de interacțiune cu utilizatorul pentru acestea, așa că trebuie să scriem interfețele de utilizator pentru aplicațiile noastre o singură dată. De remarcat, totuși, nu sunteți limitat la controalele oferite de Xamarin.Forms - puteți utiliza în continuare controalele găsite într-o singură platformă în cadrul unei aplicații Xamarin.Forms. De asemenea, putem partaja logica aplicației între platforme ca și înainte.
Statisticile de partajare a codului pentru aplicațiile dezvoltate cu Xamarin.Forms pot fi în afara topurilor. O aplicație de organizare a conferințelor are 93% din cod partajat pe iOS și 91% pe Android. Aplicația este open source. Aruncă o privire la cod.
Xamarin.Forms oferă mai mult decât controale UI. De asemenea, conține un cadru MVVM, un serviciu de mesagerie pub/sub, un API de animație și un serviciu de dependență, plus altele.
Dar astăzi, ne vom concentra pe capacitățile UI pentru construirea aplicației noastre de manager de rețete.
Aplicația pe care o vom construi
Aplicația de gestionare a rețetelor va avea o interfață de utilizator simplă. Vom lucra în bucătărie, așa că trebuie să fie ușor de folosit!
Acesta va fi format din 3 ecrane . Prima va afișa o listă cu toate rețetele încărcate în prezent în aplicație.
Apoi, atingând una dintre aceste rețete, veți putea vedea detaliile acesteia pe un al doilea ecran:
De acolo puteți atinge un buton de editare pentru a face modificări rețetei pe al treilea ecran:
De asemenea, puteți ajunge la acest ecran atingând butonul de adăugare din ecranul listei de rețete.
Mediul de dezvoltare
Aplicațiile Xamarin sunt construite cu C# și .NET, folosind Visual Studio pe Windows sau Visual Studio pentru Mac pe Mac, dar trebuie să aveți instalate, de asemenea, SDK-urile și instrumentele iOS sau Android. Instalarea totul, în ordinea corectă, ar putea fi o problemă, cu toate acestea, instalatorii Visual Studio vor avea grijă doar să instaleze IDE-ul, dar și instrumentele platformei.
Deși este întotdeauna necesar un Mac pentru a construi aplicații iOS, cu Xamarin puteți în continuare să dezvoltați și să depanați acele aplicații din Visual Studio pe Windows! Deci, dacă Windows este blocajul tău, nu este nevoie să-ți schimbi cu totul mediile.
Acum să vedem cum ne poate ajuta Xamarin.Forms să salvăm câteva rețete de familie dintr-o bază de cod!
Pagina cu listă de rețete: stabilirea interfeței de utilizare
Să începem cu a vorbi despre modul în care vom configura interfața de utilizare pentru aplicația noastră de salvare a rețetelor!
În general, fiecare ecran din Xamarin.Forms este compus din 3 elemente. O Page
. Cel puțin un element numit Layout
. Și cel puțin un Control
.
Pagina
Pagina este acel lucru care găzduiește tot ce este afișat pe ecran la un moment dat. Page
este, de asemenea, centrală în navigarea în cadrul unei aplicații.
Îi spunem lui Xamarin.Forms ce Page
să fie afișată printr-un serviciu de navigare . Serviciul respectiv se va ocupa apoi de afișarea oricărei pagini într-un mod adecvat și nativ pentru sistemul de operare.
Cu alte cuvinte, codul de navigare între ecrane a fost și el abstras!
În cele din urmă, deși nu este singurul mod de a face acest lucru, codez interfața de utilizare a Page
mele în XAML. (Calaltă modalitate ar fi să folosiți C#.) XAML este un limbaj de marcare care descrie cum arată o pagină. Și deocamdată, este suficient să spunem că este cam asemănător cu HTML.
Schema
Toate comenzile dintr-o pagină sunt aranjate de ceva numit aspect.
Una sau mai multe aspecte pot fi adăugate la o pagină.
Există mai multe tipuri diferite de Aspecte în Formulare. Unele dintre cele mai comune includ aspectele Stivă, Absolută, Relativă, Grilă, Scroll și Flex.
Controalele
Apoi, în sfârșit, sunt controalele. Acestea sunt widget-urile aplicației dvs. cu care interacționează utilizatorul.
Formularele vin cu multe comenzi care vor fi folosite indiferent de tipul de aplicație pe care o construiți. Lucruri precum etichete, butoane, casete de introducere, imagini și, desigur, vizualizări de listă.
Când adăugați un control la un ecran, îl adăugați la un aspect. Este aspectul care se ocupă de a afla unde exact pe ecran ar trebui să apară controlul.
Deci, pentru a genera următoarele ecrane pe iOS și respectiv Android:
Am folosit acest 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>
Se întâmplă câteva lucruri importante aici.
Primul este <StackLayout>
. Acest lucru îi spune Forms să aranjeze toate controalele care urmează într-o stivă.
Se întâmplă să fie un singur control în aspect, și acesta este un <ListView>
și îi vom da un nume pentru a-l putea face referire mai târziu.
Apoi, există un pic de ceremonie generală pentru ListView
înainte de a ajunge la ceea ce căutăm: <TextCell>
. Acest lucru îi spune Forms să afișeze text simplu în fiecare celulă a listei.
Spunem <TextCell>
textul pe care vrem să îl afișeze printr-o tehnică numită Data Binding . Sintaxa arată ca Text="{Binding Name}"
. Unde Name
este o proprietate a unei clase de Recipe
care modelează... Ei bine, Rețete.
Deci, cum se adaugă rețetele pe listă?
Împreună cu fiecare fișier XAML, există un fișier „cod din spatele”. Acest cod subteran ne permite să facem lucruri precum gestionarea evenimentelor de interacțiune cu utilizatorul, configurarea sau efectuarea unei alte aplicații logice.
Există o funcție care poate fi suprascrisă în fiecare Page
numită OnAppearing
- care, după cum sunt sigur că ați ghicit - este apelată atunci când apare Page
.
protected override void OnAppearing() { base.OnAppearing(); recipesList.ItemsSource = null; recipesList.ItemsSource = App.AllRecipes; }
Observați recipesList.ItemsSource = AllRecipes;
Acest lucru îi spune ListView
- „Hei! Toate datele dvs. se găsesc în App.AllRecipes
enumerabil (o variabilă la nivelul aplicației) și puteți utiliza oricare dintre proprietățile obiectului său copil pentru a le lega!”.
O listă de rețete este foarte bună - dar nu poți coace nimic fără să vezi mai întâi detaliile rețetei - și ne vom ocupa de asta în continuare.
Gestionarea evenimentelor
Fără a răspunde la atingerile utilizatorului, aplicația noastră nu este altceva decât o listă de rețete delicioase. Sună bine, dar fără să știi să le gătești, nu prea folosește!
Să facem ca fiecare celulă din ListView
să răspundă la atingeri, astfel încât să vedem cum să facem rețeta!
În fișierul cod-behind RecipeListPage
, putem adăuga handler de evenimente la controale pentru a asculta și a reacționa la evenimentele de interacțiune cu utilizatorul.
Gestionați evenimentele de atingere din vizualizarea listă, apoi:
recipesList.ItemSelected += async (sender, eventArgs) => { if (eventArgs.SelectedItem != null) { var detailPage = new RecipeDetailPage(eventArgs.SelectedItem as Recipe); await Navigation.PushAsync(detailPage); recipesList.SelectedItem = null; } };
Se întâmplă niște lucruri frumoase acolo.
Ori de câte ori cineva selectează un rând, ItemSelected
este declanșat în ListView
.
Dintre argumentele care sunt transmise în handler, obiectul eventArgs
are o proprietate SelectedItem
care se întâmplă să fie orice este legat de ListView
de mai înainte.
În cazul nostru, aceasta este clasa Recipe
. (Deci nu trebuie să căutăm obiectul în sursa principală - acesta ne este transmis.)
Pagina cu detalii rețete
Desigur, există o pagină care ne arată ingredientele secrete și direcțiile despre cum să facem fiecare rețetă, dar cum este afișată acea pagină?
Observați await Navigation.PushAsync(detailPage);
linie de sus. Obiectul Navigation
este un obiect independent de platformă care gestionează tranzițiile de pagină într-un mod nativ pentru fiecare platformă.
Acum să aruncăm o privire la pagina cu detaliile rețetei:
Această pagină este construită și cu XAML. Cu toate acestea, Layout
folosit (FlexLayout) este destul de cool, deoarece este inspirat de 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
își va aranja controalele fie în rânduri, fie în coloane. Marele beneficiu vine totuși cu faptul că poate detecta automat cât spațiu mai rămâne pe ecran pentru a plasa un control, iar dacă nu este suficient, atunci poate crea automat un nou rând sau coloană pentru a o găzdui!
Acest lucru ajută foarte mult atunci când aveți de-a face cu diferite dimensiuni de ecran, care există o mulțime în dezvoltarea mobilă.
Ei bine, având în vedere că FlexLayout
ne ajută să menținem ecranul cu detalii bine, trebuie totuși să edităm acele rețete, nu?
Probabil ai observat asta:
<ToolbarItem Text="Edit" Clicked="Edit_Clicked" />
Linia respectivă este responsabilă pentru introducerea unui buton în bara de instrumente a aplicației. Clicked="Edit_Clicked"
îi spune butonului că atunci când este apăsat, căutați în codul din spate o funcție cu acel nume și apoi executați codul acesteia.
Care, în acest caz, ar fi instanțiarea paginii de editare a rețetei și împingerea acesteia în stiva noastră de navigare folosind obiectul Navigation
menționat anterior.
Pagina Editare rețete
O pagină cu o listă de rețete: verificați! O pagina cu toate detaliile pentru a face retetele: verifica! Tot ce mai rămâne acum este să creăm pagina pe care o folosim pentru a introduce sau a schimba o rețetă în timp ce o vedem pe bunica făcându-și magia!
Mai întâi, verifică ecranele:
Și acum codul:
<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>
Există puțin mai mult cod aici și asta pentru că folosesc aspectul Grid
pentru a specifica modul în care totul ar trebui să fie aranjat într-un model 2-Dimensional.
Și, de asemenea, observați nicio legătură de date aici. Pentru că am vrut să dau un exemplu despre modul în care s-ar popula controalele doar din codul din spatele fișierului:
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(); }; }
Vezi acea proprietate TheRecipe
? Este la nivel de pagină, deține toate datele pentru o anumită rețetă și este setată în constructorul paginii.
În al doilea rând, Clicked
de evenimente Clicked pentru saveButton
și cancelButton
sunt complet .NET (și da, îmi fac propriile cuvinte destul de des.)
Eu spun că sunt .NET, deoarece sintaxa pentru a gestiona acel eveniment nu este nativă pentru Java și nici pentru Objective-C. Când aplicația rulează pe Android sau iOS, comportamentul va fi exact ca un Android Click sau iOS TouchUpInside.
Și după cum puteți vedea, fiecare dintre acești gestionatori de evenimente clic invocă funcții adecvate care fie salvează rețeta și închid pagina, fie doar închide pagina.
Iată – avem interfața de utilizare oprită pentru a salva rețetele de acum până la sfârșitul timpului!
CSS Ce?!? Sau a face aplicația drăguță
Salvând ce este mai bun pentru final: Xamarin.Forms 3.0 ne oferă, printre altele, capacitatea de a stila controalele folosind CSS!
CSS Xamarin.Forms nu este 100% ceea ce ați putea fi obișnuit din dezvoltarea web. Dar este suficient de aproape încât oricine familiarizat cu CSS se va simți ca acasă. La fel ca mine la bunica!
Deci, să luăm pagina Detalii rețetă și să o refactorăm, astfel încât să folosească Foi de stil în cascadă pentru a seta elementele vizuale în loc să seteze totul direct în XAML.
Primul pas este să creați documentul CSS! În acest caz, va arăta astfel:
.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; }
În cea mai mare parte, arată ca CSS. Sunt clase acolo. Există un singur selector pentru un tip de clasă, Image
. Și apoi o grămadă de stabilitori de proprietăți.
Unii dintre acești setatori de proprietăți, cum ar fi flex-wrap
sau flex-basis
sunt specifici pentru Xamarin.Forms. În continuare, echipa îi va prefix pe cei cu xf-
pentru a urma practicile standard.
Următorul va fi să îl aplicați controalelor 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>
Iată cum arăta înainte.
În Xamarin.Forms, pentru a face referire la documentul CSS, adăugați un <StyleSheet Source="YOUR DOC PATH" />
. Apoi puteți face referire la clasele din fiecare control prin proprietatea StyleClass
.
Cu siguranță curăță XAML și face și mai clară intenția controlului. De exemplu, acum este destul de evident ce fac acele <BoxView StyleClass="spacer" />
!
Și Image
este stilată, deoarece este o Image
și modul în care am definit selectorul în CSS.
Cu siguranță, CSS în Xamarin.Forms nu este la fel de complet implementat ca vărul său web, dar este încă destul de grozav. Aveți selectoare, clase, puteți seta proprietăți și, bineînțeles, tot acel lucru în cascadă se întâmplă!
rezumat
Trei ecrane, două platforme, un articol și rețete nesfârșite salvate! Și știi ce altceva? Puteți crea aplicații cu Xamarin.Forms pentru mai mult decât Android și iOS. Puteți construi platforme UWP, macOS și chiar Samsung Tizen!
Xamarin.Forms este un set de instrumente UI care vă permite să creați aplicații prin scrierea interfeței cu utilizatorul o dată și având interfața de utilizare redată nativ pe platformele majore.
Face acest lucru furnizând un SDK care este o abstractizare a controalelor cele mai frecvent utilizate pe platforme. În plus față de bunătatea UI, Xamarin.Forms oferă, de asemenea, un cadru MVVM cu funcții complete, un serviciu de mesagerie pub/sub, un API de animație și un serviciu de dependență.
Xamarin.Forms vă oferă, de asemenea, aceleași beneficii de cod pe care le oferă dezvoltarea tradițională Xamarin. Orice logică a aplicației este partajată pe toate platformele. Și poți să-ți dezvolți toate aplicațiile cu un singur IDE folosind o singură limbă - asta este destul de grozav!
Incotro acum? Descărcați codul sursă pentru această aplicație Xamarin.Forms pentru a o învârti singur. Apoi, pentru a afla mai multe despre Xamarin.Forms, inclusiv despre capacitatea de a crea o aplicație în browser, consultați acest tutorial online!