Tema de uma Xamarin.Forms Aplicação
Xamarin.Forms Os aplicativos podem responder a alterações de estilo dinamicamente em tempo de execução usando a DynamicResource
extensão de marcação. Essa extensão de marcação é semelhante à StaticResource
extensão de marcação, em que ambos usam uma chave de dicionário para buscar um valor de um ResourceDictionary
arquivo . No entanto, enquanto a StaticResource
extensão de marcação executa uma única pesquisa de dicionário, a DynamicResource
extensão de marcação mantém um link para a chave de dicionário. Portanto, se o valor associado à chave for substituído, a alteração será aplicada ao VisualElement
. Isso permite que o tema de tempo de execução seja implementado em Xamarin.Forms aplicativos.
O processo para implementar temas de tempo de execução em um Xamarin.Forms aplicativo é o seguinte:
- Defina os recursos para cada tema em um
ResourceDictionary
arquivo . - Consuma recursos de tema no aplicativo, usando a
DynamicResource
extensão de marcação. - Defina um tema padrão no arquivo App.xaml do aplicativo.
- Adicione código para carregar um tema em tempo de execução.
Importante
Use a StaticResource
extensão de marcação se não precisar alterar o tema do aplicativo em tempo de execução.
As capturas de tela a seguir mostram páginas temáticas, com o aplicativo iOS usando um tema claro e o aplicativo Android usando um tema escuro:
Observação
A alteração de um tema em tempo de execução requer o uso de estilos XAML e atualmente não é possível usar CSS.
Definir temas
Um tema é definido como uma coleção de objetos de recurso armazenados em um ResourceDictionary
arquivo .
O exemplo a seguir mostra o LightTheme
do aplicativo de exemplo:
<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>
O exemplo a seguir mostra o DarkTheme
do aplicativo de exemplo:
<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ThemingDemo.DarkTheme">
<Color x:Key="PageBackgroundColor">Black</Color>
<Color x:Key="NavigationBarColor">Teal</Color>
<Color x:Key="PrimaryColor">Teal</Color>
<Color x:Key="SecondaryColor">White</Color>
<Color x:Key="PrimaryTextColor">White</Color>
<Color x:Key="SecondaryTextColor">White</Color>
<Color x:Key="TertiaryTextColor">WhiteSmoke</Color>
<Color x:Key="TransparentColor">Transparent</Color>
</ResourceDictionary>
Cada um ResourceDictionary
contém Color
recursos que definem seus respectivos temas, com cada um ResourceDictionary
usando valores de chave idênticos. Para obter mais informações sobre dicionários de recursos, consulte Dicionários de recursos.
Importante
Um arquivo code-behind é necessário para cada ResourceDictionary
, que chama o InitializeComponent
método. Isso é necessário para que um objeto CLR que represente o tema escolhido possa ser criado em tempo de execução.
Definir um tema padrão
Um aplicativo requer um tema padrão, para que os controles tenham valores para os recursos que consomem. Um tema padrão pode ser definido mesclando o tema ResourceDictionary
no nível ResourceDictionary
do aplicativo definido em App.xaml:
<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>
Para obter mais informações sobre como mesclar dicionários de recursos, consulte Dicionários de recursos mesclados.
Consumir recursos de tema
Quando um aplicativo deseja consumir um recurso armazenado em um ResourceDictionary
que representa um tema, ele deve fazê-lo com a DynamicResource
extensão de marcação. Isso garante que, se um tema diferente for selecionado em tempo de execução, os valores do novo tema serão aplicados.
O exemplo a seguir mostra três estilos do aplicativo de exemplo que podem ser aplicados a Label
objetos:
<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>
Esses estilos são definidos no dicionário de recursos no nível do aplicativo, para que possam ser consumidos por várias páginas. Cada estilo consome recursos de tema com a DynamicResource
extensão de marcação.
Esses estilos são consumidos pelas páginas:
<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>
Quando um recurso de tema é consumido diretamente, ele deve ser consumido com a DynamicResource
extensão de marcação. No entanto, quando um estilo que usa a extensão de DynamicResource
marcação é consumido, ele deve ser consumido com a StaticResource
extensão de marcação.
Para obter mais informações sobre estilo, consulte Estilizando Xamarin.Forms aplicativos usando estilos XAML. Para obter mais informações sobre a extensão de DynamicResource
marcação, consulte Estilos dinâmicos no Xamarin.Forms.
Carregar um tema em tempo de execução
Quando um tema é selecionado em tempo de execução, o aplicativo deve:
- Remova o tema atual do aplicativo. Isso é obtido limpando a
MergedDictionaries
propriedade do nívelResourceDictionary
de aplicativo . - Carregue o tema selecionado. Isso é obtido adicionando uma instância do tema selecionado à
MergedDictionaries
propriedade do nívelResourceDictionary
de aplicativo .
Todos os VisualElement
objetos que definem propriedades com a extensão de DynamicResource
marcação aplicarão os novos valores de tema. Isso ocorre porque a extensão de DynamicResource
marcação mantém um link para chaves de dicionário. Portanto, quando os valores associados às chaves são substituídos, as alterações são aplicadas aos VisualElement
objetos.
No aplicativo de exemplo, um tema é selecionado por meio de uma página modal que contém um Picker
arquivo . O código a seguir mostra o OnPickerSelectionChanged
método, que é executado quando o tema selecionado é alterado:
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;
}
}
}