.NET-3.Xamarin学习与总结
Xamarin概述和介紹
- 前言
- 一、Xamarin初識?
- 1、Xamarin可以做什么
- 2、項目知識
- 二、組件
- 1.View類的屬性(通用的屬性)
- 2.與Text屬性有關的屬性:Label,Button,Entry
- 3.Image
- 4.ListView控件
- 5.Shell控件
- 6.CollectionView
- 7.彈出警報
- 8.手勢識別器(GestureRecognizer)
- 9.ActivityIndicator、ProgressBar
- 10.Check,DatePicker,Slider,Stepper
- 11.RadioButton
- 12.SearchBar
- 13.SwipeView
- 三、 布局
- 四、數據綁定
- 五、應用生命周期
- 六、模板
- 1.使用母版-詳細信息導航顯示 Xamarin.Forms 中的關系
- 2.使用 Xamarin.Forms 創建無障礙應用
- 3.使用 Xamarin.Forms 呈現器創建自定義控件
- 4.自定義 Xamarin.Forms ListView
- 5.使用共享資源和樣式設計一致的 Xamarin.Forms XAML 頁
- 6.使用 SQLite 在 Xamarin.Forms 應用中存儲本地數據
- 七、其他模塊
- 1. 持久性
- Properties 字典會自動保存到設備中。 當應用程序從后臺返回,甚或在其重啟后,添加到字典中的數據將可用。
- 2.使用命令接口ButtonDemo
- 總結
前言
Xamarin官方文檔
一、Xamarin初識?
1、Xamarin可以做什么
- Xamarin.Android Xamarin.iOS Xamarin.Mac
向 .NET 開發人員公開了完整的 Android SDK 、iOS SDK、macOS SDK
- Xamarin.Forms
一個跨平臺的UI 框架,通過 Xamarin.Forms,開發人員可從跨平臺共享代碼,生成 Android、iOS 和 Windows 應用程序。
- Xamarin.Essentials
提供了系統功能的調用,適用于Android、iOS 或 UWP 應用程序的跨平臺 API,不管如何創建用戶界面,都可以通過共享代碼進行訪問
2、項目知識
XAML文檔:用來定義界面類(UI),每個Xaml文件必須綁定2個C#文件 (類名.xaml 類名.xaml.cs 類名.xaml.g.cs )
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" //引入Xamarin.Forms命名空間 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"//引入Xaml規范命名空間 x:Class="App3.MainPage">//定義類名 </ContentPage>二、組件
1.View類的屬性(通用的屬性)
BackgroundColor ://元素的填充背景的顏色 HeightRequest , WidthRequest ://元素的高度或寬度(Height,Width為只讀屬性) MinimumHeightRequest, MinimumWidthRequest : //元素的最小高度或寬度 X,Y :// 元素的當前 X ,Y位置,只讀屬性 HorizontalOptions,VerticalOptions: //元素的水平或垂直布局方式 IsEnabled ://是否啟用此元素 IsFocused://當前是否獲得輸入焦點 IsVisible://此元素是否可見 Margin://視圖的邊距 AnchorX,AnchorY://旋轉或者縮放的中心點 RotationX,RotationY,Rotation://元素圍繞 X ,Y,Z軸的旋轉角度 ScaleX,ScaleY,Scale://應用于 X ,Y,XY方向的縮放值 Opacity://元素的不透明度值2.與Text屬性有關的屬性:Label,Button,Entry
Text://顯示的文本 TextTransform ://轉換文本None //指示不轉換文本。Default //指示將使用平臺的默認行為。 這是 TextTransform 屬性的默認值。Lowercase //指示文本將轉換為小寫。Uppercase //指示文本將轉換為大寫。 CharacterSpacing ://字符間距離 TextColor://自定義文本顏色 FontSize://字體大小 FontAttributes://字體是粗體、斜體還是兩者皆否Bold//字體為粗體。Italic字體為斜體。None字體無格式。 FontFamily://設置字體 //### 1.Label控件 TextDecorations ://將下劃線和刪除線文本修飾None Underline Strikethrough LineBreakMode : HeadTruncation //– 截斷文本的開頭,并顯示結束。CharacterWrap//– 將文本換行到字符邊界處的新行。MiddleTruncation//– 顯示文本的開頭和結尾,中間用省略號替換。NoWrap //– 不會自動換行,只顯示一行中可容納的最多文本。TailTruncation //– 顯示文本的開頭,截斷結束 FormattedText://顯示具有多種字體和顏色的文本,FormattedText屬性的類型為 FormattedString ,它包含一個或多個 Span 實例。 Span 的屬性: BackgroundColor //–跨距背景的顏色。 CharacterSpacing//,屬于 double 類型,是 Span 文本字符之間的間距。 FontAttributes //Italic–范圍中文本的字體特性。 FontFamily //–范圍內的文本的字體所屬的字體系列。 FontSize// –范圍中文本的字體大小。 LineHeight// -要應用于范圍默認行高的乘數。 Text// –范圍的文本。 TextColor// –范圍中文本的顏色。 TextDecorations //-要應用于范圍中的文本的修飾。 //案例Label <Label Text="Welcome to Xamarin.Forms!" TextColor="Blue" FontAttributes="Italic" FontSize="22" TextDecorations="Underline" HorizontalOptions="Center" /><Label TextColor="Gray" FontSize="Medium"><Label.FormattedText><FormattedString><Span Text="This sentence contains " /><Span Text="words that are emphasized, "FontAttributes="Italic" /><Span Text="and underlined."TextDecorations="Underline" /></FormattedString></Label.FormattedText></Label> //### 2.Button控件 Clicked事件://當手指點擊時觸發事件 Pressed事件://當手指按下時觸發事件 Released事件://當手指釋放時觸發事件 BorderColor://邊框顏色 BorderWidth://邊框的寬度 CornerRadius ://圓角半徑 <Button Text="Click me"Clicked="Button_Clicked" /><Button Text="Click me"Clicked="Button_Clicked"TextColor="Blue"BackgroundColor="Aqua"BorderColor="Red"BorderWidth="5"CornerRadius="5"WidthRequest="150"HeightRequest="75" /> private void Button_Clicked(object sender, EventArgs e) { ((Button)sender).Text = "這是點擊"; } //3.Entry控件、Editor控件 TextChanged://當項中的文本更改時觸發事件 Placeholder://當輸入框沒有輸入內容時,顯示的占位符文本 PlaceholderColor://控制占位符文本顏色 IsReadOnly ://禁止文本輸入 IsPassword :///內容將顯示為黑色圓圈 CursorPosition://下一個字符插入屬性中存儲的字符串的位置 SelectionLength ://選定文本的長度 Keyboard ://與用戶交互時顯示的鍵盤Chat// – 用于短信和表情符號有用的地方。 Default – 默認鍵盤。Email// – 輸入電子郵件地址時使用。 Numeric – 輸入數字時使用。Plain //– 輸入文本時使用 Telephone – 輸入電話號碼時使用。Text// – 輸入文本時使用。 Url – 用于輸入文件路徑和 Web 地址。 //案例:Entry <Entry Placeholder="Enter text"TextChanged="OnEntryTextChanged"Completed="OnEntryCompleted" /><Entry Placeholder="Enter password"MaxLength="15"IsSpellCheckEnabled="false"IsTextPredictionEnabled="false"IsPassword="true" /><Editor Placeholder="Enter multi-line text here"HeightRequest="200"TextChanged="OnEntryTextChanged"Completed="OnEntryCompleted" /> void OnEntryTextChanged(object sender, TextChangedEventArgs e) {string oldText = e.OldTextValue;string newText = e.NewTextValue;Console.WriteLine(oldText + newText); } void OnEntryCompleted(object sender, EventArgs e) {string text = ((Entry)sender).Text;Console.WriteLine(text); }3.Image
Source://用于設置要顯示的圖像,是一個ImageSource對象 可以從 本地文件、 嵌入資源、 下載或從流中加載圖像 ImageSource //類使用靜態方法獲取實例: FromFile //-需要可在每個平臺上解析的文件名或文件路徑。 FromUri //-需要 Uri 對象,例如。 new Uri("http://server.com/image.jpg") . FromResource //-需要資源標識符到應用程序或 .NET Standard 庫項目中嵌入的圖像文件,其中包含生成操作: EmbeddedResource。 FromStream //-需要提供圖像數據的流。Aspect://圖像是否拉伸、裁剪 Fill//-拉伸 ,填滿整個區域,可能會導致圖像扭曲,顯示完整圖像 AspectFill //剪輯(不拉伸)圖像,使其填充顯示區域,同時保持比例,無扭曲,圖像可能顯示不完整 AspectFit //-拉伸,將整個圖像適應顯示區域,同時保持比例,無扭曲,顯示完整圖像------------------------ //顯示圖像的其他控件 Button //具有一個 ImageSource 屬性,該屬性可設置為要在上顯示的位圖圖像 Button ImageButton// 具有 Source 可設置為要在中顯示的圖像的屬性 ImageButton 。 ToolbarItem //具有一個 IconImageSource 屬性,該屬性可設置為從文件、嵌入資源、URI 或流加載的圖像。 ImageCell //具有一個 ImageSource 屬性,該屬性可設置為從文件、嵌入資源、URI 或流中檢索的圖像。 MenuItem //具有一個 IconImageSource 屬性,可設置為要在中顯示的圖像 FlyoutItem //具有一個 Icon 屬性,可設置為要在中顯示的圖像 Tab //具有一個 Icon 屬性,可設置為要在中顯示的圖像 //案例 <Image Source="https://images2018.cnblogs.com/blog/1038566/201806/1038566-20180622142650682-1207554536.png"HeightRequest="300" /> <ImageButton Source="XamarinLogo.png"HorizontalOptions="Center"VerticalOptions="CenterAndExpand" />4.ListView控件
ItemsSource : //此屬性可接受任何實現 IEnumerable 的集合,用來指定列表中顯示的數據 ItemTemplate : //定義 ItemsSource 中每 //內置單元格一行的數據模板 TextCell //控件用于顯示文本,其中包含可選的第二行詳細信息文本。 ImageCell// 控件類似于, TextCell 但在文本左側包含一個圖像。 SwitchCell //控件用于顯示和捕獲開啟/關閉或真/假狀態。 EntryCell //控件用于顯示用戶可編輯的文本數據。 事件 ItemSelected //選擇新項時激發。 ItemTapped //點擊項時激發。5.Shell控件
Shell 包含三個主要層次結構對象:
6.CollectionView
參考官網的案例
<CollectionView><CollectionView.ItemsSource><x:Array Type="{x:Type x:String}"><x:String>Baboon</x:String><x:String>Capuchin Monkey</x:String><x:String>Blue Monkey</x:String><x:String>Squirrel Monkey</x:String><x:String>Golden Lion Tamarin</x:String><x:String>Howler Monkey</x:String><x:String>Japanese Macaque</x:String></x:Array></CollectionView.ItemsSource> </CollectionView>7.彈出警報
<Button Text="Display alert"Clicked="OnDisplayAlertButtonClicked" /><Button Text="Display alert question"Clicked="OnDisplayAlertQuestionButtonClicked" /><Button Text="Display action sheet"Clicked="OnDisplayActionSheetButtonClicked" /> async void OnDisplayAlertButtonClicked(object sender, EventArgs e) {await DisplayAlert("Alert", "This is an alert.", "OK"); } async void OnDisplayAlertQuestionButtonClicked(object sender, EventArgs e) {bool response = await DisplayAlert("Save?", "Would you like to save your data?", "Yes", "No");Console.WriteLine("Save data: " + response); } async void OnDisplayActionSheetButtonClicked(object sender, EventArgs e) {string action = await DisplayActionSheet("Send to?", "Cancel", null, "Email", "Twitter", "Facebook");Console.WriteLine("Action: " + action); }8.手勢識別器(GestureRecognizer)
GestureRecognizer 類支持對 View 實例使用點擊、收縮、平移、輕掃和拖放手勢
9.ActivityIndicator、ProgressBar
//ActivityIndicator控件定義以下屬性: 1.Color定義的顯示顏色 ActivityIndicator 的值。 2.IsRunning 一個 bool 值,該值指示是否 ActivityIndicator 應顯示、動畫顯示或隱藏。 如果值為 false , ActivityIndicator 則不可見。 <ActivityIndicator IsRunning="true" Color="Orange" /> //控件 ProgressBar 定義兩個屬性: 1.Progress 是一 float 個值,該值將當前進度表示為 0 到 1 的值。 Progress 小于 0 的值將固定為 0,大于 1 的值將固定為 1。 2.ProgressColor 是 Color 一個 ,它影響表示當前進度的內部條顏色。 <ProgressBar Progress="0.5" ProgressColor ="black"/> await progressBar.ProgressTo(0.75, 500, Easing.Linear);10.Check,DatePicker,Slider,Stepper
DatePicker,
Stepper
switch
TimePicker
11.RadioButton
單選按鈕
//Content,類型為 object,用于 string 定義 要 View 由 顯示的 RadioButton或 。 //IsChecked,類型為 bool,用于定義 RadioButton 是否選中 。 此屬性使用綁定 TwoWay ,并且 具有默認值 false。 //GroupName,類型為 string,它定義指定 RadioButton 哪些控件互斥的名稱。 此屬性的默認值為 null。 //Value,類型為 object,用于定義與 關聯的可選唯一值 RadioButton。 //BorderColor,類型為 Color,用于定義邊框筆劃顏色。 //BorderWidth,類型 double為 ,用于定義邊框 RadioButton 的寬度。 //CharacterSpacing,類型為 double,用于定義任何顯示文本的字符之間的間距。 //CornerRadius,類型為 int,用于定義 的角半徑 RadioButton。 //FontAttributes,類型為 FontAttributes,它確定文本樣式。 //FontFamily,類型為 string,用于定義字體系列。 //FontSize,類型為 double,用于定義字號。 //TextColor,類型為 Color,用于定義任何顯示文本的顏色。 //TextTransform,類型為 TextTransform,用于定義任何顯示文本的大小寫 <StackLayout><Label Text="What's your favorite animal?" /><RadioButton Content="Cat" /><RadioButton Content="Dog" /><RadioButton Content="Elephant" /><RadioButton Content="Monkey"IsChecked="true" /> </StackLayout> <StackLayout><Label Text="What's your favorite animal?" /><RadioButton Value="Cat"><RadioButton.Content><Image Source="cat.png" /></RadioButton.Content></RadioButton><RadioButton Value="Dog"><RadioButton.Content><Image Source="dog.png" /></RadioButton.Content></RadioButton><RadioButton Value="Elephant"><RadioButton.Content><Image Source="elephant.png" /></RadioButton.Content></RadioButton><RadioButton Value="Monkey"><RadioButton.Content><Image Source="monkey.png" /></RadioButton.Content></RadioButton> </StackLayout> <StackLayout RadioButtonGroup.GroupName="colors"><Label Text="What's your favorite color?" /><RadioButton Content="Red" /><RadioButton Content="Green" /><RadioButton Content="Blue" /><RadioButton Content="Other" /> </StackLayout> <Label Text="What's your favorite color?" /> <RadioButton Content="Red"GroupName="colors" /> <RadioButton Content="Green"GroupName="colors" /> <RadioButton Content="Blue"GroupName="colors1" /> <RadioButton Content="Other"GroupName="colors1" />12.SearchBar
官方文檔
//SearchButtonPressed 當用戶單擊 "搜索" 按鈕或按 "enter" 鍵時調用。 //TextChanged 只要更改了查詢框中的文本,就會調用。 <SearchBar Placeholder="Search items..."CancelButtonColor="Orange"PlaceholderColor="Orange"TextColor="Orange"TextTransform="Lowercase"HorizontalTextAlignment="Center"FontSize="Medium"FontAttributes="Italic" />13.SwipeView
官方文檔
<SwipeView><SwipeView.LeftItems><SwipeItems><SwipeItem Text="Favorite"IconImageSource="favorite.png"BackgroundColor="LightGreen"Invoked="OnFavoriteSwipeItemInvoked" /><SwipeItem Text="Delete"IconImageSource="delete.png"BackgroundColor="LightPink"Invoked="OnDeleteSwipeItemInvoked" /></SwipeItems></SwipeView.LeftItems><!-- Content --><Grid HeightRequest="60"WidthRequest="300"BackgroundColor="LightGray"><Label Text="Swipe right"HorizontalOptions="Center"VerticalOptions="Center" /></Grid> </SwipeView> //====================== <SwipeView><SwipeView.LeftItems><SwipeItems><SwipeItem Text="Favorite"IconImageSource="favorite.png"BackgroundColor="LightGreen"Invoked="OnFavoriteSwipeItemInvoked" /><SwipeItem Text="Delete"IconImageSource="delete.png"BackgroundColor="LightPink"Invoked="OnDeleteSwipeItemInvoked" /></SwipeItems></SwipeView.LeftItems><!-- Content --> </SwipeView>三、 布局
- 具有單一內容的布局:ContentView Frame ScrollView ContentPresenter
- 具有多個子元素的布局:StackLayout Grid AbsoluteLayout RelativeLayout FlexLayout
頁面(Page):下面這些類都是繼承至Page類
四、數據綁定
什么叫數據綁定?
數據綁定將兩個對象的屬性鏈接起來,某一屬性的更改將自動反映在另一個屬性中
傳統做法:基于事件驅動的模型
基于數據驅動的模型:MVVM(Model-View-ViewModel)
數據綁定:將兩個對象的屬性鏈接起來。
1.指定綁定源:在綁定上下文BindingContext中設置
2.設置綁定屬性:在綁定目標的屬性中設置
綁定模式
使用 BindingMode 枚舉的成員指定綁定模式:
Default TwoWay – 數據在源和目標之間雙向傳輸
OneWay – 數據從源到目標單向傳輸 OneWayToSource – 數據從目標到源單向傳輸
OneTime – 只有在 BindingContext 更改時,數據才從源到目標單向傳輸
Xamarin中實現數據綁定的類
BindableObject 類提供數據綁定的功能:
實現綁定源功能:
(1)實現了INotifyPropertyChanged(屬于System.ComponentModel命名空間)接口
接口中定義了:public event PropertyChangedEventHandler PropertyChanged;
PropertyChanged事件就負責通知綁定目標
(2) 當屬性的值改變時,就要觸發PropertyChanged事件,所以,屬性的set段中就要調用事件的處理函數PropertyChanged?. Invoke(this, new PropertyChangedEventArgs(propertyName));
五、應用生命周期
- 生命周期方法 : OnStart ,OnSleep 和 OnResume 。
- 頁面導航事件 : PageDisappearing /PageAppearing。
- 模式導航事件 : ModalPushedModalPopping 、和 ModalPopped 。
六、模板
1.使用母版-詳細信息導航顯示 Xamarin.Forms 中的關系
從 GitHub 克隆或下載練習存儲庫
官方文檔
什么是抽屜導航?
抽屜導航是使用滑出式抽屜來承載頁面菜單的導航模式。
什么是母版-詳細信息導航?
“母版-詳細信息導航”是一種使用兩個視圖顯示同質數據集合的方式。 母版視圖顯示整個集合的概覽。 “詳細信息”視圖顯示單個項的擴展視圖。 當用戶從該列表中選擇某項時,右側會顯示關于所選項的詳細信息。
//什么是 MasterDetailPage? 1.MasterDetailPage 是一個 Xamarin.Forms 頁面,它顯示一個母版頁和一個詳細信息頁面,并協調它們之間的同步。 Xamarin.Forms 在抽屜導航和母版-詳細信息導航中使用這一相同的類。 2. MasterDetailPage 具有兩個屬性,分別是 Master 和 Detail,它們承載每個模式的兩個邏輯部分。 這些屬性可以保存 Page 派生的類型。 在大多數應用中,你將使用派生自 ContentPage 的類型用于母版頁和詳細信息頁面。 //MasterBehavior 以及拆分式和彈出式 //split 表示始終顯示母版視圖。 //popover 表示在滑出式抽屜中顯示母版視圖。 var md = new MasterDetailPage(); md.MasterBehavior = MasterBehavior.Popover;//前面的代碼在母版頁上分配了標題 (Title)。 Xamarin.Forms 需要標題,否則會在運行時引發異常。 <ContentPage Title="Menu"><StackLayout><Button Text="Sessions" /><Button Text="Speakers" /><Button Text="Activities" /><Button Text="Rooms" /><Button Text="Map" /></StackLayout> </ContentPage>練習 - 使用 Xamarin.Forms 定義抽屜導航 UI
//分配母版頁和詳細信息頁 //母版頁 public enum PageType {Sunrise,MoonPhase,Earth,Moon,Sun,About, }<StackLayout Margin="10"><Label Text="Main Menu" FontSize="Medium" HorizontalTextAlignment="Center" /><BoxView BackgroundColor="Gray" HeightRequest="1" /><Button x:Name="btnSunrise" Text="Sunrise and Sunset" /><Button x:Name="btnMoonPhase" Text="Moon Phase" /><BoxView BackgroundColor="Gray" HeightRequest="1" /><Button x:Name="btnEarth" Text="Earth Data" /><Button x:Name="btnSun" Text="Sun Data" /><Button x:Name="btnMoon" Text="Moon Data" /><BoxView BackgroundColor="Gray" HeightRequest="1" /><Button x:Name="btnAbout" Text="About Contoso Astronomy" /> </StackLayout> public partial class AstronomyMasterPage : ContentPage{public event EventHandler<PageType> PageSelected;public AstronomyMasterPage(){InitializeComponent();btnMoonPhase.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.MoonPhase);btnSunrise.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Sunrise);btnAbout.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.About);btnEarth.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Earth);btnMoon.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Moon);btnSun.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Sun);}} //詳細信息頁public class AstronomyMasterDetailPage : MasterDetailPagepublic AstronomyMasterDetailPage() {var master = new AstronomyMasterPage();if (Device.RuntimePlatform == Device.iOS){master.IconImageSource = ImageSource.FromFile("nav-menu-icon.png");}this.Master = master;this.MasterBehavior = MasterBehavior.Popover;master.PageSelected += MasterPageSelected;PresentDetailPage(PageType.Sunrise); }void MasterPageSelected(object sender, PageType e) {PresentDetailPage(e); }void PresentDetailPage(PageType pageType) {Page page;switch (pageType){case PageType.Sunrise:page = new SunrisePage();break;case PageType.MoonPhase:page = new MoonPhasePage();break;case PageType.Earth:page = new AstronomicalBodyPage(SolarSystemData.Earth);break;case PageType.Moon:page = new AstronomicalBodyPage(SolarSystemData.Moon);break;case PageType.Sun:page = new AstronomicalBodyPage(SolarSystemData.Sun);break;case PageType.About:default:page = new AboutPage();break;}Detail = new NavigationPage(page);try{IsPresented = false;}catch { } } ///AstronomicalBody public class AstronomicalBody {public string Name { get; set; }public string Mass { get; set; }public string Circumference { get; set; }public string Age { get; set; }public string EmojiIcon { get; set; } } //SolarSystemDatapublic static class SolarSystemData {public static AstronomicalBody Sun = new AstronomicalBody(){Name = "The Sun (Sol)",Mass = "1.9855*10^30 kg",Circumference = "4,379,000 km",Age = "4.57 billion years",EmojiIcon = "??",};public static AstronomicalBody Earth = new AstronomicalBody(){Name = "Earth",Mass = "5.97237*10^24 kg",Circumference = "40,075 km",Age = "4.54 billion years",EmojiIcon = "🌎",};public static AstronomicalBody Moon = new AstronomicalBody(){Name = "Moon",Mass = "7.342*10^22 kg",Circumference = "10,921 km",Age = "4.53 billion years",EmojiIcon = "🌕",};public static AstronomicalBody HalleysComet = new AstronomicalBody(){Name = "Halley's Comet",Mass = "22 * 10^14 kg",Circumference = "11 km",Age = "4.6 billion years",EmojiIcon = "?",}; } //app將 MainPage 分配更改為 AstronomyMasterDetailPage 的實例 public App() {InitializeComponent();MainPage = new AstronomyMasterDetailPage(); } //SunrisePage //MoonPhasePage //AstronomicalBodyPage(SolarSystemData.Earth)2.使用 Xamarin.Forms 創建無障礙應用
官方文檔
練習 - 啟用系統的屏幕閱讀器
3.使用 Xamarin.Forms 呈現器創建自定義控件
了解呈現器
4.自定義 Xamarin.Forms ListView
官方文檔請在克隆或下載的練習存儲庫
- 為 ListView 創建自定義單元格布局
- 在單個 ListView 中使用多個單元格布局
- 將單元格分組為多個部分
5.使用共享資源和樣式設計一致的 Xamarin.Forms XAML 頁
官方文檔GitHub 克隆或下載練習存儲庫
- 使用資源和樣式創建一致的 UI
- 對用戶的輔助功能選項應用內置樣式
ResourceDictionary 是一個 Xamarin.Forms 庫類,可進行自定義以用于 UI 資源。 它是一個字典,因此它存儲了鍵/值對。 鍵的類型僅限于 String,而值可以是任何對象。
StaticResource 是一個標記擴展,用于在資源字典中查找資源。 提供資源的鍵后,標記擴展會返回相應的值。
在各個平臺之間,通常需要簡單調整應用的 UI。 要定義特定于平臺的值,標準方法是使用 OnPlatform 對象。
你希望實現能夠使用戶在運行時更改應用外觀的顏色主題。 StaticResource 只在字典中執行一次查找,因此無法動態地更新 UI。
可將用戶首選項存儲在 Web 服務器上,并在應用程序啟動時加載它們。 如果在字典中找不到鍵,則 StaticResource 會引發異常。
還有另外一個優點。 如果 DynamicResource 在字典中找不到鍵,它將使屬性保持為未設置狀態。 與 StaticResource 不同,缺失鍵不是錯誤,也不會引發異常。
6.使用 SQLite 在 Xamarin.Forms 應用中存儲本地數據
官方文檔克隆或下載練習存儲庫
在 Xamarin.Forms 中,有三種常用的數據本地存儲選項:
首選項:以鍵-值對的形式存儲數據
文件系統:通過文件系統訪問直接在設備上存儲松散文件
數據庫:在完整的關系數據庫中存儲數據
何時使用首選項
使用“首選項”可方便地處理簡單的數據集合。 它們通常用于讓用戶能夠配置應用程序。 例如,回到社交媒體應用程序示例,假設希望用戶能夠選擇應用程序的配色方案。 由于此選擇是一小段數據,可將用戶的選擇以鍵-值對的形式存儲在“首選項”中。
何時使用文件系統
移動設備有一個真實的文件系統,它包含由文件夾和文件構成的分層目錄結構。 擁有 XML、二進制文件或文本文件等松散文件時,使用文件系統會很方便。 例如,假設想要在設備本地存儲日志文件。 可創建一個文本文件,將其保存到文件系統,并在事件發生時將日志寫入其中。
何時使用數據庫
如果擁有數據關系或想要隨時間推移篩選數據,使用本地數據庫是個不錯的想法。 例如,在社交媒體示例中,每個帖子都包含與帖子相關的數據,例如時間戳和內容。
然而,每個帖子也與發布該帖子的用戶有關系。 最好在數據庫中表示這種關系,以防止帖子之間的數據重復,同時可提高搜索數據的效率。
什么是應用沙盒?
處理 XML 等松散文件或 SQLite 等本地數據庫文件時,需要找到存儲它們的正確位置。 應用沙盒是應用程序可以使用的專有區域。 在默認情況下,除操作系統本身外,其他任何應用程序都無法訪問此區域。
跨生命周期狀態更改保留數據
//1.App.xaml.cs public partial class App : Application {const string displayText = "displayText";public string DisplayText { get; set; }public App(){InitializeComponent();MainPage = new MainPage();}protected override void OnStart(){Console.WriteLine("OnStart");if (Properties.ContainsKey(displayText)){DisplayText = (string)Properties[displayText];}}protected override void OnSleep(){Console.WriteLine("OnSleep");Properties[displayText] = DisplayText;}protected override void OnResume(){Console.WriteLine("OnResume");} }//MainPage.xaml <StackLayout Margin="20,35,20,20"><Entry x:Name="entry"Placeholder="Enter text here"Completed="OnEntryCompleted" /> </StackLayout> protected override void OnAppearing() {base.OnAppearing();entry.Text = (Application.Current as App).DisplayText; }void OnEntryCompleted(object sender, EventArgs e) {(Application.Current as App).DisplayText = entry.Text; }練習 - 使用 SQLite 在本地存儲數據
//定義 SQLite.NET 實體 //1.將名為“Models”的新文件夾添加到“People”.NET 標準庫中。 //2.在“Models”文件夾中,創建名為“Person”的新類。 確保將其標記為“公開”。 //3.使用 [Table] 屬性批注“Person”類,并將名稱指定為“people”。 //4.將“Id”屬性指定為主鍵。 使用 [PrimaryKey] 和 [AutoIncrement] 屬性對其進行批注。 //5.向“Name”屬性添加注釋,以向數據添加一些約束。 將其 [MaxLength] 指定為 250。 指定列中的每個值都應為 [Unique]。 using SQLite; namespace People.Models {Table("people")]public class Person{[PrimaryKey, AutoIncrement]public int Id { get; set; }[MaxLength(250), Unique]public string Name { get; set; }} }//添加存儲庫類PersonRepository.cs //1.連接到數據庫 //2.向數據庫中插入行 //3.異步使用 SQLite private SQLiteConnection conn; public string StatusMessage { get; set; } ... public PersonRepository(string dbPath) {conn = new SQLiteConnection(dbPath);conn.CreateTable<Person>();//var conn = new SQLiteAsyncConnection(dbPath);//await conn.CreateTableAsync<User>(); }public void AddNewPerson(string name){int result = 0;try{//basic validation to ensure a name was enteredif (string.IsNullOrEmpty(name))throw new Exception("Valid name required");result = conn.Insert(new Person { Name = name });StatusMessage = string.Format("{0} record(s) added [Name: {1})", result, name);}catch (Exception ex){StatusMessage = string.Format("Failed to add {0}. Error: {1}", name, ex.Message);}} public List<Person> GetAllPeople() {try{return conn.Table<Person>().ToList();}catch (Exception ex){StatusMessage = string.Format("Failed to retrieve data. {0}", ex.Message);}return new List<Person>(); } ===== //public async Task AddNewPersonAsync(string name) //{ // int result = 0; // try // { // //basic validation to ensure a name was entered // if (string.IsNullOrEmpty(name)) // throw new Exception("Valid name required");// result = await conn.InsertAsync(new Person { Name = name });// StatusMessage = string.Format("{0} record(s) added [Name: {1})", result, name); // } // catch (Exception ex) // { // StatusMessage = string.Format("Failed to add {0}. Error: {1}", name, ex.Message); // } //}//public async Task<List<Person>> GetAllPeopleAsync() //{ // try // { // return await conn.Table<Person>().ToListAsync(); // } // catch (Exception ex) // { // StatusMessage = string.Format("Failed to retrieve data. {0}", ex.Message); // }// return new List<Person>(); //} //UI界面 <?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:local="clr-namespace:People"xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"ios:Page.UseSafeArea="true"x:Class="People.MainPage"><Grid Padding="5" RowSpacing="1" ColumnSpacing="1" BackgroundColor="Default"><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition Height="*" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*" /></Grid.ColumnDefinitions><Entry x:Name="newPerson"Placeholder="Enter name" /><Button Text="Add Person"Grid.Row="1"Clicked="OnNewButtonClicked" /><Label x:Name="statusMessage"Grid.Row="2" /><Button Text="Get All People"Grid.Row="3"Clicked="OnGetButtonClicked" /><ListView x:Name="peopleList"Grid.Row="4"><ListView.ItemTemplate><DataTemplate><ViewCell Height="30"><StackLayout Padding="5"><Label Text="{Binding Name}" /></StackLayout></ViewCell></DataTemplate></ListView.ItemTemplate></ListView></Grid> </ContentPage>public void OnNewButtonClicked(object sender, EventArgs args){statusMessage.Text = "";App.PersonRepo.AddNewPerson(newPerson.Text);statusMessage.Text = App.PersonRepo.StatusMessage;}public void OnGetButtonClicked(object sender, EventArgs args){statusMessage.Text = "";List<Person> people = App.PersonRepo.GetAllPeople();peopleList.ItemsSource = people;}//入口函數 string dbPath => FileAccessHelper.GetLocalFilePath("people.db3"); public static PersonRepository PersonRepo { get; private set; } public App() {InitializeComponent();PersonRepo = new PersonRepository(dbPath);MainPage = new People.MainPage();} //文件訪問幫助類 using Xamarin.Essentials; public class FileAccessHelper {public static string GetLocalFilePath(string filename){return System.IO.Path.Combine(FileSystem.AppDataDirectory, filename);} }練習 - 使用 SQLite 在本地存儲數據2
//在“NuGet 包管理器”中,選擇“瀏覽”選項卡,搜索“sqlite-net-pcl”NuGet 包 //1.Person.cs using SQLite; namespace LocalDatabaseTutorial {public class Person{[PrimaryKey, AutoIncrement]public int ID { get; set; }public string Name { get; set; }public int Age { get; set; }} } //2. Database.cs using System.Collections.Generic; using System.Threading.Tasks; using SQLite;namespace LocalDatabaseTutorial {public class Database{readonly SQLiteAsyncConnection _database;public Database(string dbPath){_database = new SQLiteAsyncConnection(dbPath);_database.CreateTableAsync<Person>().Wait();}public Task<List<Person>> GetPeopleAsync(){return _database.Table<Person>().ToListAsync();}public Task<int> SavePersonAsync(Person person){return _database.InsertAsync(person);}} } //3.在“App.xaml.cs”中 static Database database; public static Database Database {get{if (database == null){database = new Database(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "people.db3"));}return database;} }//4. MainPage.xaml <?xml version="1.0" encoding="utf-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="LocalDatabaseTutorial.MainPage"><StackLayout Margin="20,35,20,20"><Entry x:Name="nameEntry"Placeholder="Enter name" /><Entry x:Name="ageEntry"Placeholder="Enter age" /><Button Text="Add to Database"Clicked="OnButtonClicked" /><CollectionView x:Name="collectionView"><CollectionView.ItemTemplate><DataTemplate><StackLayout><Label Text="{Binding Name}"FontSize="Medium" /><Label Text="{Binding Age}"TextColor="Silver"FontSize="Small" /></StackLayout></DataTemplate></CollectionView.ItemTemplate></CollectionView></StackLayout> </ContentPage> //OnAppearing 方法覆蓋的執行是在布局 ContentPage 后但在其變得可見之前進行的。 protected override async void OnAppearing() {base.OnAppearing();collectionView.ItemsSource = await App.Database.GetPeopleAsync(); }async void OnButtonClicked(object sender, EventArgs e) {if (!string.IsNullOrWhiteSpace(nameEntry.Text) && !string.IsNullOrWhiteSpace(ageEntry.Text)){await App.Database.SavePersonAsync(new Person{Name = nameEntry.Text,Age = int.Parse(ageEntry.Text)});nameEntry.Text = ageEntry.Text = string.Empty;collectionView.ItemsSource = await App.Database.GetPeopleAsync();} }七、其他模塊
1. 持久性
Properties 字典會自動保存到設備中。 當應用程序從后臺返回,甚或在其重啟后,添加到字典中的數據將可用。
Xamarin.Forms 1.4 在 Application 類上引入了其他方法 (SavePropertiesAsync()),可調用該方法來主動保存 Properties 字典。 這是為了讓用戶能夠在重要更新后保存屬性,而不用冒因崩潰或被 OS 終止而無法將這些屬性序列化的風險。
2.使用命令接口ButtonDemo
1.頁面的跳轉,基礎設置
//app.xaml MainPage = new NavigationPage(new MainPage()); //MainPage.xamlxmlns:local="clr-namespace:student.Page" <Button Text="頁面的跳轉" Command="{Binding NavigateCommand}"CommandParameter="{x:Type local:Page1}"/>public ICommand NavigateCommand { private set; get; }NavigateCommand = new Command<Type>(async (Type pageType) => {Xamarin.Forms.Page page = (Xamarin.Forms.Page)Activator.CreateInstance(pageType);await Navigation.PushAsync(page);});BindingContext = this;2.BasicButtonClickPage.xaml
<StackLayout> <Label x:Name="label"Text="Click the Button below"FontSize="Large"VerticalOptions="CenterAndExpand" HorizontalOptions="Center" /><Button Text="Click to Rotate Text!"VerticalOptions="CenterAndExpand"HorizontalOptions="Center"Clicked="OnButtonClicked" / </StackLayout> async void OnButtonClicked(object sender, EventArgs args) {await label.RelRotateTo(360, 1000); }3.CodeButtonClickPage.cs
public CodeButtonClickPage () {Title = "Code Button Click";Label label = new Label{Text = "Click the Button below",FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),VerticalOptions = LayoutOptions.CenterAndExpand,HorizontalOptions = LayoutOptions.Center};Button button = new Button{Text = "Click to Rotate Text!",VerticalOptions = LayoutOptions.CenterAndExpand,HorizontalOptions = LayoutOptions.Center};button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);Content = new StackLayout{Children ={label,button}}; }4.BasicButtonCommandPage.xaml
xmlns:local="clr-namespace:ButtonDemos" <ContentPage.BindingContext><local:CommandDemoViewModel /> </ContentPage.BindingContext> <StackLayout><Label Text="{Binding Number, StringFormat='Value is now {0}'}"FontSize="Large"VerticalOptions="CenterAndExpand" HorizontalOptions="Center" /><Button Text="Multiply by 2"VerticalOptions="CenterAndExpand"HorizontalOptions="Center"Command="{Binding MultiplyBy2Command}" /><Button Text="Divide by 2"VerticalOptions="CenterAndExpand"HorizontalOptions="Center"Command="{Binding DivideBy2Command}" /> </StackLayout> //CommandDemoViewModel.cs class CommandDemoViewModel : INotifyPropertyChanged {double number = 1;public event PropertyChangedEventHandler PropertyChanged;public CommandDemoViewModel(){MultiplyBy2Command = new Command(() => Number *= 2);DivideBy2Command = new Command(() => Number /= 2);}public double Number{set{if (number != value){number = value;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));}}get { return number;}}public ICommand MultiplyBy2Command { private set; get; }public ICommand DivideBy2Command { private set; get; } }5.PressAndReleaseButtonPage.xaml
<StackLayout><Label x:Name="label"Text="Press and hold the Button below"FontSize="Large"VerticalOptions="CenterAndExpand" HorizontalOptions="Center" /><Button Text="Press to Rotate Text!"VerticalOptions="CenterAndExpand"HorizontalOptions="Center"Pressed="OnButtonPressed"Released="OnButtonReleased" /> </StackLayout> namespace ButtonDemos {public partial class PressAndReleaseButtonPage : ContentPage{bool animationInProgress = false;Stopwatch stopwatch = new Stopwatch();public PressAndReleaseButtonPage (){InitializeComponent ();}void OnButtonPressed(object sender, EventArgs args){stopwatch.Start();animationInProgress = true;Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>{label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);return animationInProgress;});}void OnButtonReleased(object sender, EventArgs args){animationInProgress = false;stopwatch.Stop();}} }6.ButtonAppearancePage.xaml
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:local="clr-namespace:ButtonDemos"x:Class="ButtonDemos.ButtonAppearancePage"Title="Button Appearance"><StackLayout><Button x:Name="button"Text="Button"VerticalOptions="CenterAndExpand"HorizontalOptions="Center"TextColor="{Binding Source={x:Reference textColorPicker},Path=SelectedItem.Color}"BackgroundColor="{Binding Source={x:Reference backgroundColorPicker},Path=SelectedItem.Color}"BorderColor="{Binding Source={x:Reference borderColorPicker},Path=SelectedItem.Color}" /><StackLayout BindingContext="{x:Reference button}"Padding="10"><Slider x:Name="fontSizeSlider"Maximum="48"Minimum="1"Value="{Binding FontSize}" /><Label Text="{Binding Source={x:Reference fontSizeSlider},Path=Value,StringFormat='FontSize = {0:F0}'}"HorizontalTextAlignment="Center" /><Slider x:Name="borderWidthSlider"Minimum="-1"Maximum="12"Value="{Binding BorderWidth}" /><Label Text="{Binding Source={x:Reference borderWidthSlider}, Path=Value,StringFormat='BorderWidth = {0:F0}'}"HorizontalTextAlignment="Center" /><Slider x:Name="cornerRadiusSlider"Minimum="-1"Maximum="24"Value="{Binding CornerRadius}" /><Label Text="{Binding Source={x:Reference cornerRadiusSlider}, Path=Value,StringFormat='CornerRadius = {0:F0}'}"HorizontalTextAlignment="Center" /><Grid><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /></Grid.ColumnDefinitions><Grid.Resources><Style TargetType="Label"><Setter Property="VerticalOptions" Value="Center" /></Style></Grid.Resources><Label Text="Text Color:"Grid.Row="0" Grid.Column="0" /><Picker x:Name="textColorPicker"ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"ItemDisplayBinding="{Binding FriendlyName}"SelectedIndex="0"Grid.Row="0" Grid.Column="1" /><Label Text="Background Color:"Grid.Row="1" Grid.Column="0" /><Picker x:Name="backgroundColorPicker"ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"ItemDisplayBinding="{Binding FriendlyName}"SelectedIndex="0"Grid.Row="1" Grid.Column="1" /><Label Text="Border Color:"Grid.Row="2" Grid.Column="0" /><Picker x:Name="borderColorPicker"ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"ItemDisplayBinding="{Binding FriendlyName}"SelectedIndex="0"Grid.Row="2" Grid.Column="1" /></Grid></StackLayout></StackLayout> </ContentPage>//NamedColor.cs namespace ButtonDemos {public class NamedColor {static StringBuilder stringBuilder = new StringBuilder();// Instance members.private NamedColor(){}public string Name { private set; get; }public string FriendlyName { private set; get; }public Color Color { private set; get; }public string RgbDisplay { private set; get; }// Static members.static NamedColor(){List<NamedColor> all = new List<NamedColor>();// Loop through the public static properties of the Color structure.foreach (PropertyInfo propInfo in typeof(Color).GetRuntimeProperties()){if (propInfo.GetMethod.IsPublic &&propInfo.GetMethod.IsStatic &&propInfo.PropertyType == typeof(Color)){all.Add(CreateNamedColor(propInfo.Name, (Color)propInfo.GetValue(null)));}}// Loop through the public static fields of the Color structure.foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields()){if (fieldInfo.IsPublic &&fieldInfo.IsStatic &&fieldInfo.FieldType == typeof (Color)){all.Add(CreateNamedColor(fieldInfo.Name, (Color)fieldInfo.GetValue(null)));}}all.TrimExcess();All = all;}public static IList<NamedColor> All { private set; get; }static NamedColor CreateNamedColor(string name, Color color){// Convert the name to a friendly name.stringBuilder.Clear();int index = 0;foreach (char ch in name){if (index != 0 && Char.IsUpper(ch)){stringBuilder.Append(' ');}stringBuilder.Append(ch);index++;}NamedColor namedColor = new NamedColor{Name = name,FriendlyName = stringBuilder.ToString(),Color = color,RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",(int)(255 * color.R),(int)(255 * color.G),(int)(255 * color.B))};return namedColor;}} }7.ImageButtonDemoPage.xaml
<FlexLayout Direction="Column"JustifyContent="SpaceEvenly"AlignItems="Center"><FlexLayout.Resources><Style TargetType="Button"><Setter Property="ImageSource"><OnPlatform x:TypeArguments="ImageSource"><On Platform="iOS, Android" Value="MonkeyFace.png" /><On Platform="UWP" Value="Assets/MonkeyFace.png" /></OnPlatform></Setter></Style></FlexLayout.Resources><Button><Button.ImageSource><OnPlatform x:TypeArguments="ImageSource"><On Platform="iOS, Android" Value="MonkeyFace.png" /><On Platform="UWP" Value="Assets/MonkeyFace.png" /></OnPlatform></Button.ImageSource></Button><Button Text="Default" /><Button Text="Left - 10"ContentLayout="Left, 10" /><Button Text="Top - 10"ContentLayout="Top, 10" /><Button Text="Right - 20"ContentLayout="Right, 20" /><Button Text="Bottom - 20" ContentLayout="Bottom, 20" /> </FlexLayout>總結
這是基本。總結
以上是生活随笔為你收集整理的.NET-3.Xamarin学习与总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 包打包和解析过程 unity_Unity
- 下一篇: 标准MD5 .Net,实现!的对与错!