Design einer Xamarin.Forms Anwendung
Xamarin.Forms Anwendungen können dynamisch zur Laufzeit auf Stiländerungen reagieren, indem sie die DynamicResource
Markuperweiterung verwenden. Diese Markuperweiterung ähnelt der StaticResource
Markuperweiterung, da beide einen Wörterbuchschlüssel verwenden, um einen Wert aus einem ResourceDictionary
abzurufen. Während die StaticResource
Markuperweiterung jedoch eine einzelne Wörterbuchsuche durchführt, behält die DynamicResource
Markuperweiterung einen Link zum Wörterbuchschlüssel bei. Wenn daher der dem Schlüssel zugeordnete Wert ersetzt wird, wird die Änderung auf den VisualElement
angewendet. Dadurch können Laufzeitdesigns in Xamarin.Forms Anwendungen implementiert werden.
Der Prozess zum Implementieren von Runtime-Theming in einer Xamarin.Forms Anwendung sieht wie folgt aus:
- Definieren Sie die Ressourcen für jedes Design in einem
ResourceDictionary
. - Verwenden Sie Designressourcen in der Anwendung mithilfe der
DynamicResource
Markuperweiterung. - Legen Sie ein Standarddesign in der Datei App.xaml der Anwendung fest.
- Fügen Sie Code hinzu, um ein Design zur Laufzeit zu laden.
Wichtig
Verwenden Sie die StaticResource
Markuperweiterung, wenn Sie das App-Design zur Laufzeit nicht ändern müssen.
Die folgenden Screenshots zeigen Themenseiten mit der iOS-Anwendung mit einem hellen Design und der Android-Anwendung mit einem dunklen Design:
Hinweis
Das Ändern eines Designs zur Laufzeit erfordert die Verwendung von XAML-Formatvorlagen und ist derzeit nicht mit CSS möglich.
Definieren von Designs
Ein Design ist als Auflistung von Ressourcenobjekten definiert, die in einem ResourceDictionary
gespeichert sind.
Das folgende Beispiel zeigt die LightTheme
aus der Beispielanwendung:
<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>
Das folgende Beispiel zeigt die DarkTheme
aus der Beispielanwendung:
<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>
Jede ResourceDictionary
enthält Color
Ressourcen, die ihre jeweiligen Designs definieren, wobei jedes ResourceDictionary
identische Schlüsselwerte verwendet. Weitere Informationen zu Ressourcenwörterbüchern finden Sie unter Ressourcenwörterbücher.
Wichtig
Für jede ResourceDictionary
-Datei ist eine CodeBehind-Datei erforderlich, die die InitializeComponent
-Methode aufruft. Dies ist erforderlich, damit zur Laufzeit ein CLR-Objekt erstellt werden kann, das das ausgewählte Design darstellt.
Festlegen eines Standarddesigns
Für eine Anwendung ist ein Standarddesign erforderlich, sodass Steuerelemente Werte für die Ressourcen aufweisen, die sie verbrauchen. Ein Standarddesign kann festgelegt werden, indem sie das Design ResourceDictionary
mit der Anwendungsebene ResourceDictionary
zusammenführen, die in App.xaml definiert ist:
<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>
Weitere Informationen zum Zusammenführen von Ressourcenwörterbüchern finden Sie unter Zusammengeführte Ressourcenwörterbücher.
Verwenden von Designressourcen
Wenn eine Anwendung eine Ressource nutzen möchte, die in einer ResourceDictionary
gespeichert ist, die ein Design darstellt, sollte dies mit der DynamicResource
Markuperweiterung getan werden. Dadurch wird sichergestellt, dass die Werte aus dem neuen Design angewendet werden, wenn zur Laufzeit ein anderes Design ausgewählt wird.
Das folgende Beispiel zeigt drei Stile aus der Beispielanwendung, die auf Label
Objekte angewendet werden können:
<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>
Diese Stile werden im Ressourcenwörterbuch auf Anwendungsebene definiert, sodass sie von mehreren Seiten genutzt werden können. Jede Formatvorlage nutzt Designressourcen mit der DynamicResource
Markuperweiterung.
Diese Stile werden dann von Seiten genutzt:
<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>
Wenn eine Designressource direkt genutzt wird, sollte sie mit der DynamicResource
Markuperweiterung genutzt werden. Wenn jedoch eine Formatvorlage verwendet wird, die die DynamicResource
Markuperweiterung verwendet, sollte sie mit der StaticResource
Markuperweiterung verwendet werden.
Weitere Informationen zum Formatieren finden Sie unter Formatieren Xamarin.Forms von Apps mit XAML-Formatvorlagen. Weitere Informationen zur DynamicResource
Markuperweiterung finden Sie unter Dynamische Stile in Xamarin.Forms.
Laden eines Designs zur Laufzeit
Wenn zur Laufzeit ein Design ausgewählt wird, sollte die Anwendung Folgendes ausführen:
- Entfernen Sie das aktuelle Design aus der Anwendung. Dies wird erreicht, indem die
MergedDictionaries
Eigenschaft der AnwendungsebeneResourceDictionary
entfernt wird. - Laden Sie das ausgewählte Design. Dies wird erreicht, indem der Eigenschaft der Anwendungsebene
ResourceDictionary
ein instance des ausgewählten DesignsMergedDictionaries
hinzugefügt wird.
Alle VisualElement
Objekte, die Eigenschaften mit der DynamicResource
Markuperweiterung festlegen, wenden dann die neuen Designwerte an. Dies tritt auf, weil die DynamicResource
Markuperweiterung einen Link zu Wörterbuchschlüsseln beibehält. Wenn die mit Schlüsseln verknüpften Werte ersetzt werden, werden die Änderungen daher auf die VisualElement
-Objekte angewendet.
In der Beispielanwendung wird ein Design über eine modale Seite ausgewählt, die einen Picker
enthält. Der folgende Code zeigt die OnPickerSelectionChanged
Methode, die ausgeführt wird, wenn sich das ausgewählte Design ändert:
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;
}
}
}