使用 Xamarin.Forms 保存奶奶的食譜

已發表: 2022-03-10
快速總結↬創建移動應用程序時,您必須分別為 iOS 和 Android 創建和維護用戶界面和應用程序邏輯:Objective-C/Swift 與 XCode 和 Java 與 Android Studio。 這很快就會變成一種痛苦。 但是,使用 Xamarin.Forms,您的應用程序的 UI 和應用程序邏輯駐留在單個代碼庫中,您可以使用單個 IDE 來維護這一切 — 節省時間和麻煩。 在本文中,圍繞 Xamarin.Forms 了解一下它可以為您做什麼。

我奶奶做的最好吃的,最蓬鬆的,去你膝蓋上的小圓麵包,任何人都吃過。 問題是,這些包子裡有很多秘密成分(我不只是在談論愛情),這些成分和說明都存儲在我奶奶的腦海裡。

我們都有這樣的家庭食譜,而不是可能忘記它們,在本文中,我們將使用 Xamarin.Forms 創建一個適用於 iOS 和 Android 的移動應用程序,它將為我自己和我家人的後代保存它們!

蒸汽上升的包子的繪圖
好吃的暖包子(大預覽)

因此,如果您對編寫移動應用程序感興趣,但沒有時間為每個平台一遍又一遍地編寫相同的應用程序,那麼本文適合您! 如果您不了解草莓椒鹽捲餅沙拉中的 C#,請不要擔心; 我已經編寫 Xamarin 應用程序超過 8 年,本文是 Xamarin.Forms 的導覽,旨在為您提供足夠的信息來開始自己學習。

這是什麼 Xamarin 東西?

Xamarin 不僅僅是一個有趣的詞,它允許開發人員使用與適用於 iOS 的 Swift 和 XCode 或適用於 Android 的 Java 和 Android Studio 中完全相同的 SDK 和 UI 控件來創建原生 iOS 和 Android 應用程序。

跳躍後更多! 繼續往下看↓
繪製簡筆劃,想知道他們應該為 iOS 還是 Android 開發
我應該為哪個平台開發? (大預覽)

不同之處在於應用程序是使用 .NET Framework 和 Visual Studio 或 Visual Studio for Mac 使用 C# 開發的。 然而,產生的應用程序是完全相同的。 它們的外觀、感覺和行為就像用 Objective-C、Swift 或 Java 編寫的原生應用程序一樣。

Xamarin 在代碼共享方面大放異彩。 開發人員可以使用本機控件和 SDK 為每個平台創建和定制其 UI,然後編寫一個跨平台共享的共享應用程序邏輯庫。

使用 Xamarin 為兩個平台同時開發的想法繪製簡筆劃
啊哈! 我會選擇 Xamarin! (大預覽)

正是這種代碼共享可以節省大量時間。

就像我奶奶烤的美味麵包一樣,曾經有過共享代碼的味道——很難不渴望更多——這就是 Xamarin.Forms 的用武之地。

Xamarin.Forms

Xamarin.Forms 採用了傳統 Xamarin 開發的概念,並為其添加了一層抽象。

Xamarin.Forms 沒有單獨為 iOS 和 Android 開髮用戶界面,而是引入了一個 UI 工具包,使您能夠從單個代碼庫編寫本機移動應用程序。

可以這樣想:你有一個需要一個按鈕的應用程序。 每個平台都有一個按鈕的概念。 當您知道您的應用程序的所有用戶需要做的就是點擊一個按鈕時,為什麼還要多次編寫用戶界面?

這是 Xamarin.Forms 解決的問題之一。

它為它們提供了最常用的控件和用戶交互事件的工具包,因此我們只需為我們的應用程序編寫一次用戶界面。 值得注意的是,您不僅限於 Xamarin.Forms 提供的控件 — 您仍然可以使用僅在 Xamarin.Forms 應用程序內的單個平台中找到的控件。 此外,我們可以像以前一樣在平台之間共享應用程序邏輯。

使用 Xamarin.Forms 開發的應用程序的代碼共享統計數據可能超出圖表。 一個會議組織應用程序有 93% 的代碼在 iOS 上共享,91% 在 Android 上共享。 該應用程序是開源的。 看一眼代碼。

Xamarin.Forms 提供的不僅僅是 UI 控件。 它還包含一個 MVVM 框架、一個發布/訂閱消息服務、一個動畫 API 和一個依賴服務,以及其他。

但是今天,我們將專注於構建我們的食譜管理器應用程序的 UI 功能。

我們將構建的應用程序

配方管理器應用程序將有一個簡單的用戶界面。 我們將在廚房工作,所以它需要易於使用!

它將由 3 個屏幕組成。 第一個將顯示應用程序中當前加載的所有食譜的列表。

iOS 上的食譜列表屏幕截圖
(大預覽)

然後,通過點擊其中一個食譜,您將能夠在第二個屏幕上查看其詳細信息:

iOS 上的配方詳情屏幕截圖
iOS 上的食譜詳情屏幕(大預覽)

從那裡您可以點擊編輯按鈕以在第三個屏幕上更改配方:

iOS 上的配方編輯屏幕截圖
iOS 上的食譜編輯屏幕(大預覽)

您還可以通過點擊配方列表屏幕中的添加按鈕進入此屏幕。

開發環境

Xamarin 應用程序是使用 C# 和 .NET 構建的,在 Windows 上使用 Visual Studio 或在 Mac 上使用 Visual Studio for Mac,但您還需要安裝 iOS 或 Android SDK 和工具。 以正確的順序安裝所有東西可能有點問題,但是,Visual Studio 安裝程序會注意只安裝 IDE,還要安裝平台工具。

儘管構建 iOS 應用程序始終需要 Mac,但您仍然可以使用 Xamarin 在 Windows 上從 Visual Studio 開發和調試這些應用程序! 因此,如果 Windows 是您的難題,則無需完全更改您的環境。

現在讓我們看看 Xamarin.Forms 如何幫助我們從一個代碼庫中保存一些家庭食譜!

配方列表頁面:佈局 UI

讓我們從討論如何為我們的食譜保存應用程序佈局 UI 開始吧!

總體而言,Xamarin.Forms 中的每個屏幕都由 3 個元素組成。 Page 。 至少有一個稱為Layout的元素。 並且至少有一個Control

這頁紙

頁面是同時承載屏幕上顯示的所有內容的東西。 Page也是應用內導航的中心。

在 Xamarin.Forms 中表示頁面的繪圖
頁面(大預覽)

我們通過Navigation Service告訴 Xamarin.Forms 要顯示哪個Page 。 然後,該服務將負責以適合操作系統和本機的方式顯示任何頁面。

換句話說,在屏幕之間導航的代碼也被抽象了!

最後,雖然不是唯一的方法,但我在 XAML 中對我的Page的 UI 進行了編碼。 (另一種方法是使用 C#。) XAML 是一種描述頁面外觀的標記語言。 現在,我只想說,它有點類似於 HTML。

佈局

頁面上的所有控件都由稱為佈局的東西排列。

表示 Xamarin.Forms 中的一些佈局的繪圖
佈局(大預覽)

一個或多個佈局可以添加到頁面。

繪製佈局如何與頁面交互
頁面佈局(大預覽)

表單中有幾種不同類型的佈局。 一些最常見的佈局包括 Stack、Absolute、Relative、Grid、Scroll 和 Flex 佈局。

繪製多個 Xamarin.Forms 佈局以及它們如何排列其子元素。
常見 Xamarin.Forms 佈局(大預覽)

控件

最後是控件。 這些是用戶與之交互的應用程序的小部件。

繪製幾個 Xamarin.Forms 控件,每個控件都繪製為一個框
一些控件(大預覽)

表單帶有許多控件,無論您正在構建什麼類型的應用程序,這些控件都將被使用。 標籤、按鈕、輸入框、圖像,當然還有列表視圖。

將控件添加到屏幕時,您將其添加到佈局中。 它是負責確定控件應該出現在屏幕上的確切位置的佈局。

繪製包含 2 個佈局的頁面,以及根據佈局類型排列控件的那些佈局。
一切都融為一體! (大預覽)

因此分別在 iOS 和 Android 上生成以下屏幕:

iOS 和 Android 上的食譜列表屏幕截圖
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}" 。 其中NameRecipe類的一個屬性,它模擬......好吧,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; } };

那裡有一些整潔的東西。

每當有人選擇一行時,就會在ListView上觸發ItemSelected

在傳遞給處理程序的參數中, eventArgs對像有一個SelectedItem屬性,該屬性恰好是之前綁定到ListView的任何內容。

在我們的例子中,這就是Recipe類。 (所以我們不必在主源中搜索對象 - 它會傳遞給我們。)

食譜詳情頁面

當然,有一個頁面向我們展示瞭如何製作每個食譜的秘密成分和說明,但是該頁面是如何顯示的呢?

作為準備開始烘烤的廚師打扮的簡筆劃。
我們開始做飯吧! (大預覽)

注意await Navigation.PushAsync(detailPage); 從上面的線。 Navigation對像是一個獨立於平台的對象,它以本機方式為每個平台處理頁面轉換。

現在讓我們看一下食譜詳細信息頁面:

iOS 和 Android 上的食譜詳細信息屏幕截圖
iOS(左)和 Android(右)上的食譜詳情屏幕(大預覽)

此頁面也是使用 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對象將其推送到我們的導航堆棧中。

食譜編輯頁面

帶有食譜列表的頁面:檢查! 包含製作食譜的所有詳細信息的頁面:檢查! 現在剩下的就是創建我們用來輸入或更改食譜的頁面,同時我們看著奶奶施展她的魔法!

首先,查看屏幕:

iOS 和 Android 上的配方編輯屏幕截圖
iOS(左)和 Android(右)上的配方編輯屏幕(大預覽)

現在代碼:

 <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佈局來指定所有內容應如何以二維模式佈局。

還要注意這裡沒有數據綁定。 因為我想舉一個例子,說明如何完全從文件隱藏的代碼中填充控件:

 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屬性了嗎? 它是頁面級別的,保存特定配方的所有數據,並在頁面的構造函數中設置。

其次, saveButtoncancelButtonClicked事件處理程序完全是 .NET 化的(是的,我確實經常自己造詞。)

我說它們是 .NET 化的,因為處理該事件的語法不是 Java 或 Objective-C 原生的。 當應用程序在 Android 或 iOS 上運行時,該行為將與 Android Click 或 iOS TouchUpInside 完全相同。

正如您所看到的,每個單擊事件處理程序都在調用適當的函數,這些函數要么保存配方並關閉頁面,要么只關閉頁面。

就是這樣——我們已經放下 UI 來保存從現在到時間結束的食譜!

CSS 什麼?!? 或使應用程序漂亮

將最好的留到最後:Xamarin.Forms 3.0 為我們提供了(除其他外)使用 CSS 設置控件樣式的能力!

Xamarin.Forms CSS 並非 100% 您在 Web 開發中所習慣的。 但它足夠接近,任何熟悉 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-wrapflex-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 中定義選擇器的方式。

可以肯定的是,Xamarin.Forms 中的 CSS 沒有像它的 web 表親那樣完全實現,但它仍然很酷。 你有選擇器、類、可以設置屬性,當然還有整個級聯的事情!

概括

三屏、兩個平台、一篇文章、無盡的食譜保存! 你還知道什麼嗎? 你可以使用 Xamarin.Forms 為 Android 和 iOS 以外的其他應用程序構建應用程序。 您可以構建 UWP、macOS 甚至三星 Tizen 平台!

蒸汽上升的包子的繪圖
美味的! (大預覽)

Xamarin.Forms 是一個 UI 工具包,它允許您通過編寫一次用戶界面並在主要平台上以本機方式呈現 UI 來創建應用程序。

它通過提供一個 SDK 來做到這一點,該 SDK 是跨平台最常用控件的抽象。 除了良好的 UI 之外,Xamarin.Forms 還提供了一個功能齊全的 MVVM 框架、一個發布/訂閱消息服務、一個動畫 API 和一個依賴項服務。

Xamarin.Forms 還為您提供與傳統 Xamarin 開發相同的所有代碼優勢。 任何應用程序邏輯都在所有平台之間共享。 而且您可以使用單一語言使用單一 IDE 開發所有應用程序——這非常酷!

下一步去哪裡? 下載此 Xamarin.Forms 應用程序的源代碼,親自試一試。 然後要了解有關 Xamarin.Forms 的更多信息,包括在瀏覽器中創建應用程序的能力,請查看此在線教程!