Xamarin2
- 前言
- 组件
- 一、数据绑定
- 二、Xamarin.Forms 触发器
- 三、MessagingCenter(还是很有意思)
- 四、样式(统一风格)
- 五、使用堆叠和选项卡导航创建多页 Xamarin.Forms 应用
- 推荐好看的组件UI
- 1.第三方控件推荐[Xamarin Community Toolkit](https://docs.microsoft.com/zh-cn/xamarin/community-toolkit/get-started)
- 2.[jsuarezruiz/xamarin-forms-goodlooking-UI](https://github.com/jsuarezruiz/xamarin-forms-goodlooking-UI)
- 3.[FabriBertani/XFShapeAnimatedTransitions](https://github.com/FabriBertani/XFShapeAnimatedTransitions)
前言
更加高阶的内容深入学习
组件
1.ScrollView
官方文档
ScrollView 是能够滚动其内容的布局。 ScrollView类派生自 Layout 类,默认情况下,它会垂直滚动其内容。 ScrollView只能有一个子级,尽管这可以是其他布局。
2.ListView控件
官方文档
ListView 是用于显示数据列表的视图,特别是需要滚动的长列表。
页眉和页脚
页眉和页脚组件显示在列表的开头和末尾,独立于列表的数据。 页眉和页脚可以绑定到 ListView 的数据源中的单独数据源。
组
可以对中的 ListView 数据进行分组,以便于导航。 组通常是数据绑定的。 以下屏幕截图显示了具有分组数据的 ListView :
单元
中的 ListView 数据项称为 “单元格”。 每个单元对应于一个数据行。 有一些内置单元可供选择,也可以定义自己的自定义单元。
1.通过请求刷新,用户可以请求 向下移动以刷新内容。
2.上下文操作 允许开发人员指定单个列表项的自定义操作。 例如,你可以在 3.iOS 上实现 “轻扫到操作” 或 “Android 上的长点击操作”。
4.选择 允许开发人员将功能附加到列表项的选择和 deselection 事件。
ItemsSource :
//此属性可接受任何实现 IEnumerable 的集合,用来指定列表中显示的数据
ItemTemplate :
//定义 ItemsSource 中每
//内置单元格一行的数据模板
TextCell //控件用于显示文本,其中包含可选的第二行详细信息文本。
ImageCell// 控件类似于, TextCell 但在文本左侧包含一个图像。
SwitchCell //控件用于显示和捕获开启/关闭或真/假状态。
EntryCell //控件用于显示用户可编辑的文本数据。
事件
ItemSelected //选择新项时激发。
ItemTapped //点击项时激发。
var listView = new ListView();
listView.ItemsSource = Constants.Items;
Content = listView;//重点
//一、数据源
1.简单的数据绑定
<ListView>
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>mono</x:String>
<x:String>monodroid</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
//等效于:
var listView = new ListView();
listView.ItemsSource = new string[]{ "mono","monodroid"}
//2.稍微复杂点的数据绑定
//Employee
public class Employee
{
public string DisplayName { get; set; }
}
//MainPage.cs
ObservableCollection<Employee> employees = new ObservableCollection<Employee>() { new Employee() { DisplayName = "zhouyi" } };
employees.Add(new Employee() { DisplayName = "zzl" });
ObservableCollection<string> names = new ObservableCollection<string>();
foreach (Employee employee in employees)
{
names.Add(employee.DisplayName);
}
listView.ItemsSource = names;
DisplayAlert("Item Selected", e.SelectedItem.ToString(), "Ok");
<StackLayout BackgroundColor="White">
<Label x:Name="laee" Text="{Binding Source={x:Reference listView },Path=SelectedItem}" TextColor="Red"/>
<ListView x:Name="listView"
ItemsSource="{Binding names}"
ItemSelected="listView_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding .}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
//三、定义 ListView 单元格外观
//可通过使用 ViewCell 元素进行自定义。 ViewCell元素可以显示文本和图像,指示真/假状态和接收用户输入
1.TextCell 控件用于显示文本,其中包含可选的第二行详细信息文本。
2.ImageCell 控件类似于, TextCell 但在文本左侧包含一个图像。
3.SwitchCell 控件用于显示和捕获开启/关闭或真/假状态。
4.EntryCell 控件用于显示用户可编辑的文本数据。
5.SwitchCell和 EntryCell 控件更常见地用于的上下文 TableView 中。
//TextCell(Text ,Detail ,TextColor ,DetailColor )
//ImageCell(Text ,Detail,TextColor ,DetailColor,ImageSource )
//footer、header
<ListView.Header>
<StackLayout Orientation="Horizontal">
<Label Text="Header"
TextColor="Olive"
BackgroundColor="Red" />
</StackLayout>
</ListView.Header>
<ListView.Footer>
<StackLayout Orientation="Horizontal">
<Label Text="Footer"
TextColor="Gray"
BackgroundColor="Blue" />
</StackLayout>
</ListView.Footer>
一、数据绑定
数据绑定将两个对象的属性链接起来,如此,对某一属性的更改将自动反映在另一个属性中。
官方文档
1.基本绑定
Xamarin.Forms 数据绑定连接两个对象之间的一对属性,其中至少有一个通常是用户界面对象。 这两个对象称为“目标”和“源” :
“目标”是设置数据要绑定的对象(和属性)。
“源”是数据绑定引用的对象(和属性)。
//一.使用上下文绑定
//BindingContext 属性指定源对象。
//SetBinding 方法指定目标属性和源属性。
//1.基本代码绑定
<Label x:Name="label"
Text="TEXT"
FontSize="48"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
// label.SetBinding(Label.RotationProperty, new Binding("Value", source: slider));//另一种方法
//2.基本 Xaml 绑定1
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}"
//BindingContext="{x:Reference slider}"
//Rotation="{Binding Value}"//简写/>
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="CenterAndExpand" />
//3.基本 Xaml 绑定2
<Label Text="TEXT"
FontSize="40"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Scale="{Binding Source={x:Reference slider},
Path=Value}" />
//Scale="{Binding Value, Source={x:Reference slider}}" />第二种
//<Label.Scale>第三种
//<Binding Source="{x:Reference slider}"
// Path="Value" />
//</Label.Scale>
<Slider x:Name="slider"
Minimum="-2"
Maximum="2"
VerticalOptions="CenterAndExpand" />
//4.绑定上下文继承
<StackLayout VerticalOptions="FillAndExpand"
BindingContext="{x:Reference slider}">
<Label Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="EndAndExpand"
Rotation="{Binding Value}" />
<BoxView Color="#800000FF"
WidthRequest="180"
HeightRequest="40"
HorizontalOptions="Center"
VerticalOptions="StartAndExpand"
Rotation="{Binding Value}" />
</StackLayout>
<Slider x:Name="slider"
Maximum="360" />
//5.反向绑定
//Label 是数据绑定源,而 Slider 是目标。 绑定引用 Label 的 Opacity 属性,其默认值为 1。
//Slider 从 Label 的初始 Opacity 值初始化为值 1。
<Label x:Name="label"
Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Slider x:Name="slider"
VerticalOptions="CenterAndExpand"
Value="{Binding Source={x:Reference label},
Path=Opacity}" />
//6.StringFormat 属性
<Slider x:Name="slider" />
<Label Text="{Binding Source={x:Reference slider},
Path=Value,
StringFormat='The slider value is {0:F2}'}" />
//StringFormat='The Entry text is "{0}"'
//F2 的格式设置规范导致值在显示时会带两个小数位数。
2.绑定模式
使用 BindingMode 枚举的成员指定绑定模式:
Default
TwoWay –数据在源和目标之间的双向
OneWay –数据从源到目标进行
OneWayToSource –数据从目标到源
OneTime – data 从源到目标进行处理,但仅当 BindingContext 更改
//大多数可绑定属性的默认绑定模式都是 OneWay,但以下属性的默认绑定模式为 TwoWay:
//DatePicker 的 Date 属性
//Editor、Entry、SearchBar 和 EntryCell 的 Text 属性
//ListView 的 IsRefreshing 属性
//MultiPage 的 SelectedItem 属性
//Picker 的 SelectedIndex 和 SelectedItem 属性
//Slider 和 Stepper 的 Value 属性
//Switch 的 IsToggled 属性
//SwitchCell 的 On 属性
//TimePicker 的 Time 属性
二、Xamarin.Forms 触发器
//1.属性触发器 单个组件
//TargetType - 触发器适用的控件类型。
//Property - 要监视的控件上的属性。
//Value-出现监视属性时的值,这会导致触发器激活。
//Setter - Setter 元素的集合,可进行添加且在满足触发条件时使用。 必须指定要设置的 Property 和 Value。
<Entry Placeholder="enter name">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
<!-- multiple Setters elements are allowed -->
</Trigger>
</Entry.Triggers>
</Entry>
//2.使用 style 应用触发器
//还可将触发器添加到控件、页面或应用程序 ResourceDictionary 中的 Style 声明。 下面的示例声明隐式 style(即未设置 Key);也就是说,它应用于页面上的所有 Entry 控件。
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Style.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter Property="BackgroundColor" Value="Yellow" />
<!-- multiple Setters elements are allowed -->
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
//3.数据触发器
//当输入为空时,触发器将禁用该按钮。
<Entry x:Name="entry"
Text=""
Placeholder="required field" />
<Button x:Name="button" Text="Save"
FontSize="Large"
HorizontalOptions="Center">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference entry},
Path=Text.Length}"
Value="0">
<Setter Property="IsEnabled" Value="False" />
<!-- multiple Setters elements are allowed -->
</DataTrigger>
</Button.Triggers>
</Button>
//4.事件触发器
//触发器操作实现应该:
1.实现泛型 TriggerAction<T> 类,并且泛型参数对应于触发器将应用到的控件类型。 可以使用 VisualElement 之类的超类编写适用于多种控件的触发器操作,或指定 Entry 等控件类型。
2.Invoke重写方法-只要满足触发器条件,就会调用此方法。
<Entry Placeholder="Enter a System.Double">
<Entry.Triggers>
<EventTrigger Event="TextChanged">
<local:NumericValidationTriggerAction />
</EventTrigger>
</Entry.Triggers>
</Entry>
//local:NumericValidationTriggerAction.cs
public class NumericValidationTriggerAction : TriggerAction<Entry>
{
protected override void Invoke (Entry entry)
{
double result;
bool isValid = Double.TryParse (entry.Text, out result);
entry.TextColor = isValid ? Color.Default : Color.Red;
}
}
//5.多触发器(我觉得很难)
//触发 Setter 前,所有条件必须为 true。
<Entry x:Name="email"
Text=""
Placeholder="email" />
<Entry x:Name="phone"
Text=""
Placeholder="phone" />
<Button x:Name="button" Text="Save"
FontSize="Large"
HorizontalOptions="Center">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference email},
Path=Text.Length}"
Value="0" />
<BindingCondition Binding="{Binding Source={x:Reference phone},
Path=Text.Length}"
Value="0" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="False" />
</MultiTrigger>
</Button.Triggers>
</Button>
//生成“全部需要”的多触发器
MultiTriggerConverter.cs
public class MultiTriggerConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if ((int)value > 0)
return true; // data has been entered
else
return false; // input is empty
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException ();
}
}
MultiTriggerXaml.xaml
<ContentPage.Resources>
<ResourceDictionary>
<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
</ResourceDictionary>
</ContentPage.Resources>
<Entry x:Name="user"
Text=""
Placeholder="user name" />
<Entry x:Name="pwd"
Text=""
Placeholder="password" />
<Button x:Name="loginButton" Text="Login"
FontSize="Large"
HorizontalOptions="Center"
IsEnabled="false">
<Button.Triggers>
<MultiTrigger TargetType="Button">
<MultiTrigger.Conditions>
<BindingCondition Binding="{Binding Source={x:Reference user},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
<BindingCondition Binding="{Binding Source={x:Reference pwd},
Path=Text.Length,
Converter={StaticResource dataHasBeenEntered}}"
Value="true" />
</MultiTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiTrigger>
</Button.Triggers>
</Button>
//6.EnterActions 和 ExitActions
//全局的
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Style.Triggers>
<Trigger TargetType="Entry"
Property="Entry.IsFocused" Value="True">
<Trigger.EnterActions>
<local:FadeTriggerAction StartsFrom="0" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<local:FadeTriggerAction StartsFrom="1" />
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
//单个
<Entry Placeholder="enter job title" Text="">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="Entry.IsFocused" Value="True">
<Trigger.EnterActions>
<local:FadeTriggerAction StartsFrom="0" />
</Trigger.EnterActions>
<Trigger.ExitActions>
<local:FadeTriggerAction StartsFrom="1" />
</Trigger.ExitActions>
</Trigger>
</Entry.Triggers>
</Entry>
FadeTriggerAction.cs
public class FadeTriggerAction : TriggerAction<VisualElement>
{
public int StartsFrom { set; get; }
protected override void Invoke(VisualElement sender)
{
sender.Animate("FadeTriggerAction", new Animation((d) =>
{
var val = StartsFrom == 1 ? d : 1 - d;
// so i was aiming for a different color, but then i liked the pink :)
sender.BackgroundColor = Color.FromRgb(1, val, 1);
}),
length: 1000, // milliseconds
easing: Easing.Linear);
}
}
//7.比较状态触发器
<?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="WorkingWithTriggers.CompareStateTriggerDemoPage"
Title="CompareStateTrigger demo">
<ContentPage.Resources>
<Style TargetType="Grid">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup>
<VisualState x:Name="Checked">
<VisualState.StateTriggers>
<CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
Value="True" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="Black" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Unchecked">
<VisualState.StateTriggers>
<CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
Value="False" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="White" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<Grid>
<Frame BackgroundColor="White"
CornerRadius="12"
Margin="24"
HorizontalOptions="Center"
VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<CheckBox x:Name="checkBox"
VerticalOptions="Center" />
<Label Text="Check the CheckBox to modify the Grid background color."
VerticalOptions="Center" />
</StackLayout>
</Frame>
</Grid>
</ContentPage>
三、MessagingCenter(还是很有意思)
发布-订阅模式是一种消息传递模式,在此模式下,发布者可在无需知道任何接收方(称为订阅方)的情况下发送消息。 同样,订阅方可在不了解任何发布方的情况下侦听特定消息。
//发布方使用 MessagingCenter.Send 方法发送消息,而订阅方使用
//MessagingCenter.Subscribe 方法侦听消息。 此外,订阅方还可以使用
//MessagingCenter.Unsubscribe 方法取消消息订阅(如果需要)。
//MainPage.xaml
<StackLayout Margin="20,35,20,20">
<Label Text="MessagingCenter Demo"
FontAttributes="Bold"
HorizontalOptions="Center" />
<Button Text="Say Hi"
Clicked="OnSayHiButtonClicked" />
<Button Text="Say Hi to John"
Clicked="OnSayHiToJohnButtonClicked" />
<Button Text="Unsubscribe"
Clicked="OnUnsubscribeButtonClicked" />
<ListView ItemsSource="{Binding Greetings}" />
</StackLayout>
//MainPage.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel();//这里很是重点。
// Subscribe to a message (which the ViewModel has also subscribed to) to display an alert
MessagingCenter.Subscribe<MainPage, string>(this, "Hi", async (sender, arg) =>
{
await DisplayAlert("Message received", "arg=" + arg, "OK");
});
}
void OnSayHiButtonClicked(object sender, EventArgs e)
{
MessagingCenter.Send<MainPage>(this, "Hi");
}
void OnSayHiToJohnButtonClicked(object sender, EventArgs e)
{
MessagingCenter.Send<MainPage, string>(this, "Hi", "John");
}
async void OnUnsubscribeButtonClicked(object sender, EventArgs e)
{
MessagingCenter.Unsubscribe<MainPage, string>(this, "Hi");
await DisplayAlert("Unsubscribed", "This page has stopped listening, so no more alerts. However, the ViewModel is still receiving messages.", "OK");
}
}
MainPageViewModel.cs
public class MainPageViewModel
{
public ObservableCollection<string> Greetings { get; set; }
public MainPageViewModel()
{
Greetings = new ObservableCollection<string>();
MessagingCenter.Subscribe<MainPage>(this, "Hi", (sender) =>
{
Greetings.Add("Hi");
});
MessagingCenter.Subscribe<MainPage, string>(this, "Hi", (sender, arg) =>
{
Greetings.Add("Hi " + arg);
});
}
}
四、样式(统一风格)
使用 XAML 样式设置应用样式
传统上, Xamarin.Forms 设置应用的样式是使用 Style 类将属性值集合分组到一个对象中,然后可应用于多个可视元素实例。 这有助于减少重复标记,并允许更轻松地更改应用外观。
使用 设置应用样式级联样式表
Xamarin.Forms 支持使用 CSS 设置级联样式表 (设置) 。 样式表由规则列表组成,每个规则由一个或多个选择器以及声明块组成。
使用 XAML 样式设置应用样式
全局样式<页面级别<控件级别
通过对控件类型进行分组和设置属性来创建自定义控件外观的样式。
-
显式样式
显式样式是通过设置 控件的属性有选择地应用于控件的样式。 -
隐式样式
隐式样式是指所有相同 的控件使用的样式,无需每个控件都引用该样式。 -
全局样式
可以通过将样式添加到应用程序的 ResourceDictionary 来全局使用样式。 这有助于避免跨页面或控件的样式的重复。 -
样式继承
样式可以从其他样式继承,以减少重复并实现重复使用。 -
动态样式
样式不会对属性更改做出响应,并在应用程序持续时间内保持不变。 但是,应用程序可以使用动态资源在运行时动态响应样式更改。 -
设备样式
Xamarin.Forms在类中 包含六个Xamarin.Forms样式,称为设备样式。 所有六种样式只能应用 Label 于实例。 -
样式类
Xamarin.Forms 样式类可以将多个样式应用于控件,而无需采用样式继承。
//一、显示样式
//页面级别
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="labelStyle" TargetType="Label">
<Setter Property="TextColor" Value="Black"/>
<Setter Property="FontSize" Value="7"/>
<Setter Property="FontAttributes" Value="Italic"/>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />
//控件级别
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="labelRedStyle" TargetType="Label">
<Setter Property="TextColor" Value="Black"/>
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Label Text="These labels" Style="{StaticResource labelRedStyle}" />
</StackLayout>
</ContentPage.Content>
//二、隐式样式
//页面级别
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="HorizontalOptions" Value="Fill" />
<Setter Property="VerticalOptions" Value="CenterAndExpand" />
<Setter Property="BackgroundColor" Value="Yellow" />
<Setter Property="FontAttributes" Value="Italic" />
<Setter Property="TextColor" Value="Blue" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Entry Text="These entries" />
<Entry Text="are demonstrating" />
<Entry Text="implicit styles," />
<Entry Text="implicit style override" BackgroundColor="Lime" TextColor="Red" />
<local:CustomEntry Text="not receiving the style" />
</StackLayout>//不接受样式
</ContentPage.Content>
//CustomEntry.cs
public class CustomEntry : Entry
{
}
//控件级别
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style TargetType="Entry">
<Setter Property="HorizontalOptions" Value="Fill" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<Entry Text="These entries" />
</StackLayout>
</ContentPage.Content>
//将样式应用于派生类型
<Style TargetType="Button"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="Red" />
</Style>
//将此样式置于页面级别ResourceDictionaryButton将导致它应用于页面上的所有实例,以及从 派生的任何控件Button。
//但是,如果 ApplyToDerivedTypes 属性保持未设置,则样式将仅应用于 Button 实例。
//三、全局样式
//应用程序级别app.xaml
<Application.Resources>
<ResourceDictionary>
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="HorizontalOptions"
Value="Center" />
<Setter Property="VerticalOptions"
Value="CenterAndExpand" />
<Setter Property="BorderColor"
Value="Lime" />
<Setter Property="CornerRadius"
Value="5" />
<Setter Property="BorderWidth"
Value="5" />
<Setter Property="WidthRequest"
Value="200" />
<Setter Property="TextColor"
Value="Teal" />
</Style>
<!-- ContentPage -->
<Style TargetType="ContentPage"
ApplyToDerivedTypes="True">
<Setter Property="BackgroundColor"
Value="WhiteSmoke" />
</Style>
</ResourceDictionary>
</Application.Resources>
//四、样式继承
//遵循继承链
//应用程序级别资源只能继承自其他应用程序级别资源。
//页面级别资源可以继承自应用程序级别资源和其他页面级资源。
//控制级别资源可以从应用程序级别资源、页面级别资源和其他控制级别资源继承。
//属性设置为 BasedOn 实例实现的 Style
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
<Setter Property="HorizontalOptions"
Value="Center" />
<Setter Property="VerticalOptions"
Value="CenterAndExpand" />
</Style>
<Style x:Key="labelStyle" TargetType="Label"
BasedOn="{StaticResource baseStyle}">
<Setter Property="TextColor" Value="Teal" />
</Style>
<Style x:Key="buttonStyle" TargetType="Button"
BasedOn="{StaticResource baseStyle}">
<Setter Property="BorderColor" Value="Lime" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="These labels"
Style="{StaticResource labelStyle}" />
<Button Text="So is the button"
Style="{StaticResource buttonStyle}" />
</StackLayout>
</ContentPage.Content>
//遵循继承链
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="labelStyle" TargetType="Label" BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="buttonStyle" TargetType="Button" BasedOn="{StaticResource baseStyle}">
...
</Style>
</ResourceDictionary>
</StackLayout.Resources>
...
</StackLayout>
</ContentPage.Content>
//五、动态样式
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
<Style x:Key="blueSearchBarStyle"
TargetType="SearchBar"
BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="greenSearchBarStyle"
TargetType="SearchBar">
...
</Style>
...
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<SearchBar Placeholder="These SearchBar controls"
Style="{DynamicResource searchBarStyle}" />
...
</StackLayout>
</ContentPage.Content>
DynamicStylesPage .cs
public partial class DynamicStylesPage : ContentPage
{
bool originalStyle = true;
public DynamicStylesPage ()
{
InitializeComponent ();
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
}
void OnButtonClicked (object sender, EventArgs e)
{
if (originalStyle) {
Resources ["searchBarStyle"] = Resources ["greenSearchBarStyle"];
originalStyle = false;
} else {
Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
originalStyle = true;
}
}
}
//动态样式继承
//使用 属性无法从动态样式派生 Style.BasedOn 样式。 相反, Style 类包含 BaseResourceKey 属性,该属性可设置为其值可能会动态更改的字典键。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesInheritancePage" Title="Dynamic Inheritance" IconImageSource="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="baseStyle" TargetType="View">
...
</Style>
<Style x:Key="blueSearchBarStyle" TargetType="SearchBar" BasedOn="{StaticResource baseStyle}">
...
</Style>
<Style x:Key="greenSearchBarStyle" TargetType="SearchBar">
...
</Style>
<Style x:Key="tealSearchBarStyle" TargetType="SearchBar" BaseResourceKey="searchBarStyle">
...
</Style>
...
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<SearchBar Text="These SearchBar controls" Style="{StaticResource tealSearchBarStyle}" />
...
</StackLayout>
</ContentPage.Content>
</ContentPage>
//六、设备样式
//在 Device 类中包含六种动态样式,称为设备样式。
//BodyStyle
//CaptionStyle
//ListItemDetailTextStyle
//ListItemTextStyle
//SubtitleStyle
//TitleStyle
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DeviceStylesPage" Title="Device" IconImageSource="xaml.png">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="myBodyStyle" TargetType="Label"
BaseResourceKey="BodyStyle">
<Setter Property="TextColor" Value="Accent" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="0,20,0,0">
<Label Text="Title style"
Style="{DynamicResource TitleStyle}" />
<Label Text="Subtitle text style"
Style="{DynamicResource SubtitleStyle}" />
<Label Text="Body style"
Style="{DynamicResource BodyStyle}" />
<Label Text="Caption style"
Style="{DynamicResource CaptionStyle}" />
<Label Text="List item detail text style"
Style="{DynamicResource ListItemDetailTextStyle}" />
<Label Text="List item text style"
Style="{DynamicResource ListItemTextStyle}" />
<Label Text="No style" />
<Label Text="My body style"
Style="{StaticResource myBodyStyle}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
//七、样式类
1.创建样式类
<ContentPage ...>
<ContentPage.Resources>
<Style TargetType="BoxView"
Class="Separator">
<Setter Property="BackgroundColor"
Value="#CCCCCC" />
<Setter Property="HeightRequest"
Value="1" />
</Style>
<Style TargetType="BoxView"
Class="Rounded">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="10" />
</Style>
<Style TargetType="BoxView"
Class="Circle">
<Setter Property="BackgroundColor"
Value="#1FAECE" />
<Setter Property="WidthRequest"
Value="100" />
<Setter Property="HeightRequest"
Value="100" />
<Setter Property="HorizontalOptions"
Value="Start" />
<Setter Property="CornerRadius"
Value="50" />
</Style>
<Style TargetType="VisualElement"
Class="Rotated"
ApplyToDerivedTypes="true">
<Setter Property="Rotation"
Value="45" />
</Style>
</ContentPage.Resources>
<StackLayout Margin="20">
<BoxView StyleClass="Separator" />
<BoxView WidthRequest="100"
HeightRequest="100"
HorizontalOptions="Center"
StyleClass="Rounded, Rotated" />
<BoxView HorizontalOptions="Center"
StyleClass="Circle" />
</StackLayout>
</ContentPage>
使用 Xamarin.Forms CSS 级联样式表
五、使用堆叠和选项卡导航创建多页 Xamarin.Forms 应用
1.使用 NavigationPage 实现堆叠导航
导航堆栈上还必须至少有一个页面。 NavigationPage 类提供了一个构造函数,该函数使用堆栈的初始或根页面参数。 在此代码中,我们将传递 HomePage 类的一个实例作为要显示的初始页面,然后将新的 NavigationPage 设置为应用的初始页面。
//提供的方法,,模式导航的方法(需要实践去理解)
Task PushAsync(Page page, bool animated);
Task PushAsync(Page page); // 'animated' is true
Task<Page> PopAsync(bool animated);
Task<Page> PopAsync(); // 'animated' is true
-------------------------
IReadOnlyList<Page> ModalStack { get; }
Task PushModalAsync(Page page);
Task<Page> PopModalAsync();
IReadOnlyList<Page> NavigationStack { get; }
Task PushAsync(Page page);
Task<Page> PopAsync();
//app.cs根页面
MainPage = new NavigationPage(new MainPage());
//调用方法,调用模式导航方法
await this.Navigation.PushAsync(new Page1());
await this.Navigation.PopAsync();
await Navigation.PushModalAsync(new EditPage());
await Navigation.PopModalAsync();
//MainPage()页面
<StackLayout>
...
<Button x:Name="btnSunrise" Text="Sunrise and Sunset" />
<Button x:Name="btnMoonPhase" Text="Moon Phase" />
<Button x:Name="btnSpaceInfo" Text="Astronomical Bodies" />
<Button x:Name="btnAbout" Text="About Contoso Astronomy" />
</StackLayout>
public MainPage()
{
InitializeComponent();
//初始化添加导航
btnSunrise.Clicked += (s, e) => Navigation.PushAsync(new SunrisePage());
btnMoonPhase.Clicked += (s, e) => Navigation.PushAsync(new MoonPhasePage());
btnSpaceInfo.Clicked += (s, e) => Navigation.PushAsync(new AstronomicalBodiesPage());
btnAbout.Clicked += (s, e) => Navigation.PushAsync(new AboutPage());
}
//处理设备后退按钮(用处巨大)
//替代该方法可以让我们在页面关闭前完成一些工作。 由我们决定应执行的操作。
protected override bool OnBackButtonPressed()//方法重写
{
...
}
2.选项卡导航创建多页
推荐好看的组件UI
1.第三方控件推荐Xamarin Community Toolkit
许多好用得组件值得一试
2.jsuarezruiz/xamarin-forms-goodlooking-UI
这个仓库集成了许多多好看的UI仓库的总结与介绍。
3.FabriBertani/XFShapeAnimatedTransitions
这个仓库是有关页面切换的动画效果(值得参考,可以当做轮子来使用)