.NET-3.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 包含三个主要层次结构对象:
- FlyoutItem:表示飞出项;每个 FlyoutItem 对象都是 Shell 对象的子对象。
- Tab:显示为底部选项卡导航; 每个 Tab 对象都是 FlyoutItem 对象子对象。
- ShellContent:显示为顶部选项卡 ;每个 ShellContent 对象都是 Tab 对象的子对象;ShellContent 的内容属性是ContentPage 对象。
Shell 的菜单项:MenuItem控件
Shell的页头:Shell.FlyoutHeader
Shell的页脚:Shell. FlyoutFooter
Shell禁止飞出页面:TabBar
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 实例使用点击、收缩、平移、轻扫和拖放手势
1. TapGestureRecognizer
Tapped 事件 Command属性
2. SwipeGestureRecognizer
Direction属性:Left,Right,Up,Down
Swiped事件:参数SwipedEventArgs ,Direction属性(SwipeDirection.Left, Right,Up,Down )
Command属性
3. PinchGestureRecognizer
PinchUpdated 事件
参数PinchGestureUpdatedEventArgs:
Status属性:动作状态(GestureStatus.Running,Started,Completed) ,
Scale属性:自上次接收到更新后的用户缩放手势的相对大小
ScaleOrigin属性:缩放手势的已更新的原点
4. PanGestureRecognizer
PanUpdated 事件
参数PanUpdatedEventArgs :
StatusType属性:动作状态(GestureStatus.Running,Started,Completed)
TotalX属性:获取手势开始后 X 方向的总体更改
TotalY属性:获取手势开始后 Y 方向的总体更改
5. DragGestureRecognizer
此类定义了以下属性:
CanDrag:类型为 bool,指明手势识别器附加到的元素能否为拖动源。 此属性的默认值为 true。
DragStartingCommand:类型为 ICommand,在第一次识别拖动手势时执行。
DragStartingCommandParameter,属于 object 类型,是传递给 DragStartingCommand 的参数。
DropCompletedCommand:类型为 ICommand,在放置拖动源时执行。
DropCompletedCommandParameter,属于 object 类型,是传递给 DropCompletedCommand 的参数。
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
//CheckBox 是可以选中或空的按钮类型。 选中复选框后,它将被视为已启用。 如果复选框为空,则将其视为关闭
//1.CheckBox 定义一个 bool 名为 IsChecked 的属性,指示是否 CheckBox 选中。默认绑定模式为 BindingMode.TwoWay
//2.定义一个 CheckedChanged 事件,该事件在属性更改时
<CheckBox IsChecked="True" CheckedChanged="OnCheckBoxCheckedChanged"
Color="Red"/>
<CheckBox x:Name="checkBox" />
<Label Text="Lorem ipsum dolor sit amet, elit rutrum, enim hendrerit augue vitae praesent sed non, lorem aenean quis praesent pede.">
<Label.Triggers>
<DataTrigger TargetType="Label"
Binding="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
Value="true">
<Setter Property="FontAttributes"
Value="Italic, Bold" />
<Setter Property="FontSize"
Value="Large" />
</DataTrigger>
</Label.Triggers>
</Label>
//复选框可视状态
<CheckBox >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="Color"
Value="Red" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="IsChecked">
<VisualState.Setters>
<Setter Property="Color"
Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</CheckBox>
//DatePicker调用平台的日期选取器控件
//MinimumDate 类型的 DateTime,默认为 1900 年的第一天。
//MaximumDate 类型的 DateTime,默认为 2100 年的最后一天。
//Date 类型 DateTime为 的所选日期,默认为值 DateTime.Today。
//Format类型为 stringFormatstring .NET 格式设置字符串,默认为"D",即长日期模式。
//TextColor 类型 Color为 的颜色,用于显示所选日期,默认为 Color.Default。
//FontAttributes 类型的 FontAttributes,默认为 FontAtributes.None。
//FontFamily 类型的 string,默认为 null。
//FontSize 类型的 double,默认为 -1.0。
//CharacterSpacing,属于 double 类型,是 DatePicker 文本字符之间的间距。
//slider 滑块
//Minimum 是范围的最小值,默认值为 0。
//Maximum 是范围的最大值,默认值为 1。
//Value 是滑块的值,该值介于 和 MinimumMaximum 之间,默认值为 0。
//MinimumTrackColor 是滚动块左侧的条形颜色。
//MaximumTrackColor 是滚动块右边的条形颜色。
//ThumbColor 是滚动块颜色。
//ThumbImageSource 是用于 thumb 的图像,类型为 ImageSource。
//Stepper
//Increment 是按 更改所选值的数量,默认值为 1。
//Minimum 是范围的最小值,默认值为 0。
//Maximum 是范围的最大值,默认值为 100。
//Value 是 stepper 的值,该值介于 和 MinimumMaximum 之间,默认值为 0。
//定义一个 ValueChanged 事件
//switch
//IsToggled boolean指示是否IsToggled的 Switch 值。
//OnColor是一个 Color ,它会影响在切换或OnColor状态下呈现的 Switch 方式。
//ThumbColorColor是交换机拇指的。
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类
//ContentPage:是最简单且最常见的页面类型。 将 Content 属性设置为一个 View 对象。
//NavigationPage:使用基于堆栈的体系结构管理其他页面中的导航。 在应用程序中使用页面导航时,主页的实例应传递给NavigationPage对象的构造函数。
//FlyoutPage :管理两个页面。 将 Flyout 属性设置为通常显示列表或菜单的页面。 将 Detail 属性设置为一个页面。
//TabbedPage:允许使用选项卡在子页间导航。 将 Children 属性设置为页的集合
//CarouselPage:允许通过手指轻扫在子页面之间导航。 将 Children 属性设置为页的集合。
//TemplatedPage:使用控件模板显示全屏内容,是的基类 ContentPage 。
//Shell:提供大多数应用程序需要的基本 UI 功能,让你能够专注于处理应用程序的核心工作负载
<StackLayout Margin="20,35,20,20">
<StackLayout Margin="20,35,20,25" Orientation="Horizontal">
<Label Text="The StackLayout has its Margin property set, to control the rendering position of the StackLayout." />
<Label Text="The Padding property can be set to specify the distance between the StackLayout and its children." />
<Label Text="The Spacing property can be set to specify the distance between views in the StackLayout." />
</StackLayout>
<Label Text="The Grid has its Margin property set, to control the rendering position of the Grid." />
<Grid Margin="20,35,20,20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Label Text="Column 0, Row 0" />
<Label Grid.Column="1"
Text="Column 1, Row 0" />
<Label Grid.Row="1"
Text="Column 0, Row 1" />
<Label Grid.Column="1"
Grid.Row="1"
Text="Column 1, Row 1" />
</Grid>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Label Grid.ColumnSpan="2"
Text="This text uses the ColumnSpan poperty to span both columns." />
<Label Grid.Row="1"
Grid.RowSpan="2"
Text="This text uses the RowSpan property to span two rows." />
</Grid>
</StackLayout>
四、数据绑定
什么叫数据绑定?
数据绑定将两个对象的属性链接起来,某一属性的更改将自动反映在另一个属性中
传统做法:基于事件驱动的模型
基于数据驱动的模型: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 。
//OnStart - 在启动应用程序时调用它。
//OnSleep - 每当应用程序转入后台时调用它。
//OnResume - 应用程序发送到后台后恢复时调用
//PageAppearing - 页面即将在屏幕上显示时引发。
//PageDisappearing - 页面即将从屏幕上消失时引发。
//ModalPushing - 按模式推送页面时将引发它。
//ModalPushed - 按模式推送页面后将引发它。
//ModalPopping - 按模式弹出页面时将引发它。
//ModalPopped - 按模式弹出页面后将引发它。
protected override void OnStart()//应用程序启动时调用 OnStart 方法。
{
Console.WriteLine("OnStart");
}
protected override void OnSleep()//应用程序转到后台时调用 OnSleep 方法。
{
Console.WriteLine("OnSleep");
}
protected override void OnResume()//应用程序从后台恢复时调用 OnResume 方法。
{
Console.WriteLine("OnResume");
}
六、模板
1.使用母版-详细信息导航显示 Xamarin.Forms 中的关系
- 对于母版视图,在拆分视图或者弹出式视图之间进行选择
- 使用弹出式抽屉导航在页面之间进行切换
- 使用母版 - 详细信息拆分视图显示集合
什么是抽屉导航?
抽屉导航是使用滑出式抽屉来承载页面菜单的导航模式。
什么是母版-详细信息导航?“母版-详细信息导航”是一种使用两个视图显示同质数据集合的方式。 母版视图显示整个集合的概览。 “详细信息”视图显示单个项的扩展视图。 当用户从该列表中选择某项时,右侧会显示关于所选项的详细信息。
//什么是 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 : MasterDetailPage
public 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; }
}
//SolarSystemData
public 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 创建无障碍应用
官方文档
练习 - 启用系统的屏幕阅读器
//IsInAccessibleTree 是布尔值,可告知操作系统元素是否应可供访问并对屏幕阅读器可见。
//Name 是屏幕阅读器用于公告元素的简短的描述性文本字符串
<ActivityIndicator AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.Name="Progress indicator" />
//HelpText 是元素的较长说明。 可将它视为元素的工具提示。
<Button Text="Toggle"
AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.HelpText="Toggles the activity indicator" />
//LabeledBy 允许其他元素为当前元素定义辅助功能文本。
<Label x:Name="label" Text="Enter your name: " />
<Entry AutomationProperties.IsInAccessibleTree="true"
AutomationProperties.LabeledBy="{x:Reference label}" />
3.使用 Xamarin.Forms 呈现器创建自定义控件
了解呈现器
4.自定义 Xamarin.Forms ListView
- 为 ListView 创建自定义单元格布局
- 在单个 ListView 中使用多个单元格布局
- 将单元格分组为多个部分
5.使用共享资源和样式设计一致的 Xamarin.Forms XAML 页
- 使用资源和样式创建一致的 UI
- 对用户的辅助功能选项应用内置样式
- 什么是 ResourceDictionary?
ResourceDictionary 是一个 Xamarin.Forms 库类,可进行自定义以用于 UI 资源。 它是一个字典,因此它存储了键/值对。 键的类型仅限于 String,而值可以是任何对象。
- 使用 StaticResource 应用资源
StaticResource 是一个标记扩展,用于在资源字典中查找资源。 提供资源的键后,标记扩展会返回相应的值。
- OnPlatform 作为资源
在各个平台之间,通常需要简单调整应用的 UI。 要定义特定于平台的值,标准方法是使用 OnPlatform 对象。
- 使用并更新动态资源
你希望实现能够使用户在运行时更改应用外观的颜色主题。 StaticResource 只在字典中执行一次查找,因此无法动态地更新 UI。
可将用户首选项存储在 Web 服务器上,并在应用程序启动时加载它们。 如果在字典中找不到键,则 StaticResource 会引发异常。
还有另外一个优点。 如果 DynamicResource 在字典中找不到键,它将使属性保持为未设置状态。 与 StaticResource 不同,缺失键不是错误,也不会引发异常。
<Label TextColor="Blue" FontSize="14">
<Button TextColor="Blue" FontSize="14">
//可以将文本颜色定义为资源,而不是重复它。 该定义类似于此 XAML
<Color x:Key="PageControlTextColor">Blue</Color>
<Page.Resources>
<Color x:Key="PageControlTextColor">Blue</Color>
</Page.Resources>
//使用 StaticResource 应用资源
<Page.Resources>
<Color x:Key="PageControlTextColor">Blue</Color>
</Page.Resources>
...
<Label TextColor="{StaticResource PageControlTextColor}" ... />
//OnPlatform 作为资源
<Page.Resources>
<OnPlatform x:Key="textColor"
x:TypeArguments="Color"
iOS="Silver"
Android="Green" />
</Page.Resources>
...
<Label TextColor="{StaticResource textColor}" ... />
<Page.Resources>
<ResourceDictionary>
<Color x:Key="bgColor">#c0c0c0</Color>
<Color x:Key="fgColor">#606060</Color>
</ResourceDictionary>
</Page.Resources>
<Grid x:Name ="LayoutRoot" BackgroundColor="{StaticResource bgColor}" Padding="10">
<Label x:Name="tipOutput" Text="0.00" TextColor="{StaticResource fgColor}" FontSize="22" Grid.Row="1" Grid.Column="1" />
//什么是 DynamicResource?
<ContentPage ...>
<Page.Resources>
<Color x:Key="PanelBackgroundColor">Blue</Color>
</Page.Resources>
<StackLayout BackgroundColor="{DynamicResource PanelBackgroundColor}">
...
</StackLayout>
</ContentPage>
6.使用 SQLite 在 Xamarin.Forms 应用中存储本地数据
在 Xamarin.Forms 中,有三种常用的数据本地存储选项:
首选项:以键-值对的形式存储数据
文件系统:通过文件系统访问直接在设备上存储松散文件
数据库:在完整的关系数据库中存储数据
-
何时使用首选项
使用“首选项”可方便地处理简单的数据集合。 它们通常用于让用户能够配置应用程序。 例如,回到社交媒体应用程序示例,假设希望用户能够选择应用程序的配色方案。 由于此选择是一小段数据,可将用户的选择以键-值对的形式存储在“首选项”中。 -
何时使用文件系统
移动设备有一个真实的文件系统,它包含由文件夹和文件构成的分层目录结构。 拥有 XML、二进制文件或文本文件等松散文件时,使用文件系统会很方便。 例如,假设想要在设备本地存储日志文件。 可创建一个文本文件,将其保存到文件系统,并在事件发生时将日志写入其中。 -
何时使用数据库
如果拥有数据关系或想要随时间推移筛选数据,使用本地数据库是个不错的想法。 例如,在社交媒体示例中,每个帖子都包含与帖子相关的数据,例如时间戳和内容。
然而,每个帖子也与发布该帖子的用户有关系。 最好在数据库中表示这种关系,以防止帖子之间的数据重复,同时可提高搜索数据的效率。 -
什么是应用沙盒?
处理 XML 等松散文件或 SQLite 等本地数据库文件时,需要找到存储它们的正确位置。 应用沙盒是应用程序可以使用的专有区域。 在默认情况下,除操作系统本身外,其他任何应用程序都无法访问此区域。
//在 Android 上访问应用沙盒,
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
//使用 Xamarin.Essentials 访问库文件夹
var libFolder = FileSystem.AppDataDirectory;
跨生命周期状态更改保留数据
//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 entered
if (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.xaml
xmlns: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>
总结
这是基本。