Xamarin.Forms之主题
Xamarin.Forms应用程序可以使用DynamicResource标记扩展在运行时动态响应样式更改。
此标记扩展类似于StaticResource标记扩展,两者都使用字典键从ResourceDictionary中获取值。 但是,在StaticResource标记扩展执行单个字典查找的同时,DynamicResource标记扩展维护与字典键的链接。 因此,如果替换了与键关联的值,则更改将应用于VisualElement。 这使得可以在Xamarin.Forms应用程序中实现运行时主题。
在Xamarin.Forms应用程序中实现运行时主题的过程如下:
- 创建一个xaml文件,继承ResourceDictionary,并在其中为每个主题定义资源。
- 使用DynamicResource标记扩展在应用程序中使用主题资源。
- 在应用程序的App.xaml文件中设置默认主题。
- 添加代码以在运行时加载主题。
定义主题
创建xaml文件,主题定义为存储在ResourceDictionary中的资源对象的集合。
以下示例显示了示例应用程序中的LightTheme:
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ThemingDemo.LightTheme"> <Color x:Key="PageBackgroundColor">White</Color> <Color x:Key="NavigationBarColor">WhiteSmoke</Color> <Color x:Key="PrimaryColor">WhiteSmoke</Color> <Color x:Key="SecondaryColor">Black</Color> <Color x:Key="PrimaryTextColor">Black</Color> <Color x:Key="SecondaryTextColor">White</Color> <Color x:Key="TertiaryTextColor">Gray</Color> <Color x:Key="TransparentColor">Transparent</Color> </ResourceDictionary>
每个ResourceDictionary包含定义各自主题的Color资源,每个ResourceDictionary使用相同的键值。 有关资源字典的更多信息,请参见资源字典。
注:每个ResourceDictionary都需要cs隐藏代码,该代码调用InitializeComponent方法,这是必需的,以便可以在运行时创建表示所选主题的CLR对象。
设置默认主题
应用程序需要默认主题,以便控件具有它们消耗的资源的值。 可以通过将主题的ResourceDictionary合并到App.xaml中定义的应用程序级ResourceDictionary来设置默认主题:
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ThemingDemo.App"> <Application.Resources> <ResourceDictionary Source="Themes/LightTheme.xaml" /> </Application.Resources> </Application>
使用主题资源
当应用程序要使用存储在代表主题的ResourceDictionary中的资源时,应使用DynamicResource标记扩展名进行操作。 这样可以确保如果在运行时选择了其他主题,则将应用新主题中的值。
下面的示例显示了示例 应用程序中可以应用于Label对象的三种样式:
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ThemingDemo.App"> <Application.Resources> <Style x:Key="LargeLabelStyle" TargetType="Label"> <Setter Property="TextColor" Value="{DynamicResource SecondaryTextColor}" /> <Setter Property="FontSize" Value="30" /> </Style> <Style x:Key="MediumLabelStyle" TargetType="Label"> <Setter Property="TextColor" Value="{DynamicResource PrimaryTextColor}" /> <Setter Property="FontSize" Value="25" /> </Style> <Style x:Key="SmallLabelStyle" TargetType="Label"> <Setter Property="TextColor" Value="{DynamicResource TertiaryTextColor}" /> <Setter Property="FontSize" Value="15" /> </Style> </Application.Resources> </Application>
这些样式在应用程序级 资源字典中定义(主题的xaml文件中),以便它们可以被多个页面使用。 每种样式都使用DynamicResource标记扩展来消耗主题资源。
这些样式随后被页面使用:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:ThemingDemo" x:Class="ThemingDemo.UserSummaryPage" Title="User Summary" BackgroundColor="{DynamicResource PageBackgroundColor}"> ... <ScrollView> <Grid> <Grid.RowDefinitions> <RowDefinition Height="200" /> <RowDefinition Height="120" /> <RowDefinition Height="70" /> </Grid.RowDefinitions> <Grid BackgroundColor="{DynamicResource PrimaryColor}"> <Label Text="Face-Palm Monkey" VerticalOptions="Center" Margin="15" Style="{StaticResource MediumLabelStyle}" /> ... </Grid> <StackLayout Grid.Row="1" Margin="10"> <Label Text="This monkey reacts appropriately to ridiculous assertions and actions." Style="{StaticResource SmallLabelStyle}" /> <Label Text=" • Cynical but not unfriendly." Style="{StaticResource SmallLabelStyle}" /> <Label Text=" • Seven varieties of grimaces." Style="{StaticResource SmallLabelStyle}" /> <Label Text=" • Doesn't laugh at your jokes." Style="{StaticResource SmallLabelStyle}" /> </StackLayout> ... </Grid> </ScrollView> </ContentPage>
直接使用主题资源时,应使用DynamicResource标记扩展来使用。 但是,当使用了使用DynamicResource标记扩展的样式时,应将其与StaticResource标记扩展一起使用。
在运行时加载主题
在运行时选择主题时,应用程序应:
- 从应用程序中删除当前主题。 通过清除应用程序级ResourceDictionary的MergedDictionaries属性来实现。
- 加载所选主题。 这是通过将所选主题的实例添加到应用程序级ResourceDictionary的MergedDictionaries属性中来实现的。
任何使用DynamicResource标记扩展设置属性的VisualElement对象都将应用新的主题值。 发生这种情况是因为DynamicResource标记扩展保留了到字典键的链接。 因此,当替换与键关联的值时,所做的更改将应用于VisualElement对象。
在示例应用程序中,通过包含Picker的模式页面选择主题。 以下代码显示了OnPickerSelectionChanged方法,该方法在选定主题更改时执行:
void OnPickerSelectionChanged(object sender, EventArgs e) { Picker picker = sender as Picker; Theme theme = (Theme)picker.SelectedItem; ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries; if (mergedDictionaries != null) { mergedDictionaries.Clear(); switch (theme) { case Theme.Dark: mergedDictionaries.Add(new DarkTheme()); break; case Theme.Light: default: mergedDictionaries.Add(new LightTheme()); break; } } }