Design einer Xamarin.Forms Anwendung
Xamarin.Forms Anwendungen können dynamisch auf Formatänderungen zur Laufzeit reagieren, indem sie die DynamicResource
Markuperweiterung verwenden. Diese Markuperweiterung ist der StaticResource
-Markuperweiterung insofern ähnlich, als beide einen Wörterbuchschlüssel verwenden, um einen Wert aus einem ResourceDictionary
zu extrahieren. Während die StaticResource
-Markuperweiterung eine einzelne Wörterbuchsuche durchführt, behält die DynamicResource
-Markuperweiterung einen Link zum Wörterbuchschlüssel bei. Wenn also der dem Schlüssel zugeordnete Wert ersetzt wird, wird die Änderung auf das VisualElement
angewendet. Dadurch können Laufzeitdesigns in Xamarin.Forms Anwendungen implementiert werden.
Der Prozess für die Implementierung des Laufzeitdesigns in einer Xamarin.Forms Anwendung lautet wie folgt:
- 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 App.xaml-Datei 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 nicht zur Laufzeit ändern müssen.
Die folgenden Screenshots zeigen Designseiten 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 wird als eine Sammlung von Ressourcenobjekten definiert, die in einem ResourceDictionary
gespeichert sind.
Das folgende Beispiel zeigt die LightTheme
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
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>
Jedes ResourceDictionary
enthält Color
-Ressourcen, die ihre jeweiligen Designs definieren, wobei jedes ResourceDictionary
identische Schlüsselwerte verwendet. Weitere Informationen zu Ressourcenverzeichnissen finden Sie unter Ressourcenverzeichnisse.
Wichtig
Für jedes ResourceDictionary
, das die InitializeComponent
-Methode aufruft, ist eine CodeBehind-Datei erforderlich. Nur so kann zur Laufzeit ein CLR-Objekt erstellt werden, das das ausgewählte Design repräsentiert.
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 das Design ResourceDictionary
in der anwendungsebene ResourceDictionary
zusammengeführt wird, 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 Ressourcenverzeichnissen finden Sie unter Zusammengeführte Ressourcenverzeichnisse.
Verwenden von Designressourcen
Wenn eine Anwendung eine Ressource nutzen möchte, die in einem ResourceDictionary
Design gespeichert ist, das ein Design darstellt, sollte dies mit der DynamicResource
Markuperweiterung ausgeführt werden. Dadurch wird sichergestellt, dass bei der Auswahl eines anderen Designs zur Laufzeit die Werte des neuen Designs verwendet werden.
Das folgende Beispiel zeigt drei Formatvorlagen 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 Ressourcenverzeichnis auf Anwendungsebene definiert, sodass sie von mehreren Seiten genutzt werden können. Jede Formatvorlage verwendet Designressourcen mit der DynamicResource
-Markuperweiterung.
Diese Formatvorlagen werden dann von Seiten verwendet:
<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 verwendet wird, sollte dies mit der DynamicResource
-Markuperweiterung geschehen. Wenn jedoch eine Formatvorlage verwendet wird, die die DynamicResource
-Markuperweiterung verwendet, sollte dies mit der StaticResource
-Markuperweiterung geschehen.
Weitere Informationen zum Formatieren finden Sie unter Formatieren Xamarin.Forms von Apps mit XAML-Formatvorlagen. Weitere Informationen zur DynamicResource
Markuperweiterung finden Sie unter Dynamische Formatvorlagen in Xamarin.Forms.
Laden eines Designs während der Laufzeit
Wenn ein Design zur Laufzeit ausgewählt wird, sollte die Anwendung Folgendes ausführen:
- Entfernen Sie das aktuelle Design aus der Anwendung. Dies wird durch Löschen der
MergedDictionaries
Eigenschaft der AnwendungsebeneResourceDictionary
erreicht. - Das ausgewählte Design laden. Dies wird durch Hinzufügen einer Instanz des ausgewählten Designs zur
MergedDictionaries
Eigenschaft der AnwendungsebeneResourceDictionary
erreicht.
Alle VisualElement
-Objekte, die Eigenschaften mit der DynamicResource
-Markuperweiterung festlegen, wenden dann die neuen Designwerte an. Dies geschieht, da die DynamicResource
-Markuperweiterung einen Link zu Verzeichnisschlüsseln enthä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;
}
}
}