Controlli come Page
e View
forniscono proprietà per definirne l’aspetto, la forma e il comportamento all’interno del’app. In particolare, l’aspetto di un controllo può essere gestito attraverso la realizzazione di stili o, più semplicemente, tramite dei template basilari per l’app. Ciononostante, questo approccio non offre una netta separazione tra l’aspetto della pagina e il suo contenuto.
Dalla versione 2.0, Xamarin ha introdotto il componente ControlTemplate
, che offre una netta separazione tra l’aspetto e il contenuto di una Page
o di una View
, permettendo allo sviluppatore di concentrarsi esclusivamente sull’aspetto dei controlli.
Un ControlTemplate
può essere applicato ai seguenti tipi di View
e Page
impostando l’omonima proprietà:
ContentPage
ContentView
TemplatedPage
TemplatedView
dove la TemplatedPage
è la classe base per le ContentPage
e mostra il contenuto a schermo intero impiegando un ControlTemplate
, mentre la TemplatedView
è la classe base della ContentView
.
Un ControlTemplate
può essere definito sia in XAML che in C#:
XAML | Viene impiegata la proprietà ResourceDictionary che assegna il ControlTemplate creato alla collezione Resources di una pagina (o in generale) dell’app |
---|---|
C# | Viene definita una pagina o una classe, che può essere globalmente acceduta |
Inoltre, è possibile applicare un ControlTemplate
su due livelli:
- page-level: applicazione solo ad una pagina;
- application-level: applicazione a tutte le pagine dell’app.
La definizione di questi livelli prevede la seguente gerarchia: supponendo di aver definito due differenti ControlTemplate
, uno per ogni livello con il medesimo nome, quello definito per l’application-level viene sostituito dal template per il page-level.
Creazione di un ControlTemplate in XAML
La creazione di un template per l’application-level prevede che la classe App del progetto Portable sia sostituita dalla sua implementazione alternativa basata su XMAL e C#. Ciò rende più semplice la creazione di un nuovo template in XAML. La nuova classe App implementerà nel code-behind la classe Application
per poter utilizzare la proprietà Resources
che conterrà al suo interno il nuovo ControlTemplate
.
Nel codice XAML della classe App
si definirà il seguente codice:
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="HelloXamarin.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="HeaderFooterTemplate">
...
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
Attraverso la proprietà Resources
di Application
è possibile definire un ResourceDictionary
, un dizionario di risorse che possono essere impiegate all’interno di un’app Xamarin.Forms e facilmente riutilizzate. Ogni nuova risorsa contenuta nel ResourceDictionary
è caratterizzata da una chiave x:Key
definita come proprietà dell’elemento che si desidera creare. In questo caso, la chiave è associata al ControlTemplate
che definisce al suo interno gli elementi del template.
Ad esempio, si supponga di voler definire per tutte le pagine una schermata composta da un header ed un footer come nella seguente figura:
Il modo più semplice è per implementare tale layout è definire una Grid
composta da tre Row
, ognuna con una dimensione diversa e due colonne. Inoltre, ogni riga conterrà rispettivamente:
- l’header composto da una
BoxView
che funge da sfondo, unImage
racchiusa nella prima colonna e unaLabel
racchiusa nella seconda colonna; - un
ContentPresenter
che svolge il ruolo di layout manager per i template e definisce dove il contenuto che verrà aggiunto all’interno di ogni singola pagina deve andare, evitando così sovrapposizioni con l’header e il footer; - il footer composto da uno
StackLayout
che farà da contenitore per laLabel
. Si noti che alternativamente si può impiegare unaBoxView
come per l’header e viceversa.
Nel codice XAML si avrà:
<ControlTemplate x:Key="HeaderFooterTemplate">
<Grid BackgroundColor="#003366">
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"/>
<RowDefinition Height="0.85*" />
<RowDefinition Height="0.05*" />
</Grid.RowDefinitions>
<BoxView Grid.ColumnSpan="2" Color="#c7c9cc" />
<Image Grid.Column="1" VerticalOptions="CenterAndExpand" HorizontalOptions="Center">
<Image.Source>
<OnPlatform x:TypeArguments="ImageSource"
iOS="logo.png"
Android="logo.png"
WinPhone="Images/logo.png" />
</Image.Source>
</Image>
<Label Grid.Column="0" Text="Header!!!" TextColor="Black" FontSize="22" VerticalOptions="Center" />
<ContentPresenter Grid.Row="1" Grid.ColumnSpan="2" />
<StackLayout Grid.Row="2" Grid.ColumnSpan="2" BackgroundColor="#c7c9cc">
<Label Text="Footer here!" TextColor="Black" FontSize="18" VerticalOptions="CenterAndExpand" HorizontalOptions="Center"/>
</StackLayout>
</Grid>
</ControlTemplate>
Per impostare il ControlTemplate
in una pagina dell’applicazione, basterà richiamare l’omonima proprietà. Ad esempio, una volta creata la pagina CTApplicationLevel, nel codice XAML si avrà:
<ContentPage ControlTemplate="{StaticResource HeaderFooterTemplate}">
<StackLayout VerticalOptions="CenterAndExpand">
<Label Text="||| Page content |||" TextColor="Black" FontSize="25" HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
Eseguendo quindi l’app sui tre OS di interesse si otterrà il risultato in figura.
Se per una specifica pagina si volesse impiegare un template differente, ad esempio con colori e posizioni degli elementi invertiti, si potrà definrie un ControlTemplate
per la pagina lavora sul codice XAML della pagina stessa. Si supponga quindi di aver creato la pagina CTPageLevel, nel codice XAML si avrà:
<ContentPage.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="HeaderFooterTemplate">
<Grid BackgroundColor="#003366">
. . .
</Grid>
</ControlTemplate>
</ResourceDictionary>
</ContentPage.Resources>
Analogamente a quanto fatto per la nuova classe App, anche qui è necessario richiamare la proprietà Resources
della ContentPage
e definire all’interno del ResourceDictionary
il nuovo template avente come chiave la stessa definita per il template per l’application-level. Effettuando le opportune modifiche ed eseguendo l’applicazione si otterrà il seguente risultato.