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;
}
}
}
来源:oschina
链接:https://my.oschina.net/u/4380991/blog/3359301