Navigazione gerarchica
La classe NavigationPage offre un'esperienza di navigazione gerarchica in cui l'utente è in grado di scorrere le pagine avanti e indietro in base alle esigenze. La classe implementa la navigazione come stack LIFO (Last-In, First-Out) di oggetti Pagina. Questo articolo illustra come usare la classe NavigationPage per eseguire la navigazione in uno stack di pagine.
Per passare da una pagina all'altra, un'applicazione esegue il push di una nuova pagina nello stack di navigazione, in cui diventa la pagina attiva, come illustrato nel diagramma seguente:
Per tornare alla pagina precedente, l'applicazione preleva la pagina corrente dallo stack di navigazione e la nuova pagina in primo piano diventa la pagina attiva, come illustrato nel diagramma seguente:
I metodi di navigazione sono esposti dalla proprietà Navigation
in qualsiasi tipo di Page
derivata. Questi metodi consentono di eseguire il push di pagine nello stack di navigazione, di prelevare pagine dallo stack di navigazione e di eseguire la manipolazione dello stack.
Esecuzione degli spostamenti
Nella navigazione gerarchica la classe NavigationPage
viene usata per navigare in uno stack di oggetti ContentPage
. Gli screenshot seguenti illustrano i componenti principali della NavigationPage
in ogni piattaforma:
Il layout di una NavigationPage
dipende dalla piattaforma:
- In iOS è presente una barra di spostamento nella parte superiore della pagina che include un titolo e un pulsante Indietro che consente di tornare alla pagina precedente.
- In Android è presente una barra di spostamento nella parte superiore della pagina che include un titolo, un'icona e un pulsante Indietro che consente di tornare alla pagina precedente. L'icona è definita nell'attributo
[Activity]
che decora la classeMainActivity
nel progetto specifico della piattaforma Android. - Nella piattaforma UWP (Universal Windows Platform) è presente una barra di spostamento nella parte superiore della pagina che visualizza un titolo.
In tutte le piattaforme, il valore della proprietà Page.Title
verrà visualizzato come titolo della pagina. Inoltre, la IconColor
proprietà può essere impostata su un Color
oggetto applicato all'icona nella barra di spostamento.
Nota
È consigliabile popolare una NavigationPage
solo con istanze di ContentPage
.
Creazione della pagina radice
La prima pagina aggiunta a uno stack di navigazione è definita pagina radice dell'applicazione e il codice seguente illustra come viene eseguita questa operazione:
public App ()
{
MainPage = new NavigationPage (new Page1Xaml ());
}
In questo modo viene eseguito il push dell'istanza Page1Xaml
ContentPage
nello stack di navigazione, in cui diventa la pagina attiva e la pagina radice dell'applicazione. Ciò viene illustrato negli screenshot seguenti:
Nota
La proprietà RootPage
di un'istanza NavigationPage
fornisce l'accesso alla prima pagina nello stack di navigazione.
Eseguire il push delle pagine nello stack di navigazione
Per passare a Page2Xaml
è necessario chiamare il metodo PushAsync
sulla proprietà Navigation
della pagina corrente, come illustrato nell'esempio di codice seguente:
async void OnNextPageButtonClicked (object sender, EventArgs e)
{
await Navigation.PushAsync (new Page2Xaml ());
}
Di conseguenza l'istanza Page2Xaml
viene inserita tramite push nello stack di navigazione, in cui diventa la pagina attiva. Ciò viene illustrato negli screenshot seguenti:
Quando si richiama il metodo PushAsync
, si verificano gli eventi seguenti:
- Per la pagina che chiama
PushAsync
viene richiamato l'override diOnDisappearing
. - Per la pagina di destinazione dello spostamento viene richiamato l'override di
OnAppearing
. - L'attività
PushAsync
viene completata.
Tuttavia, l'ordine preciso in cui si verificano questi eventi è dipendente dalla piattaforma. Per altre informazioni, vedere il capitolo 24 del libro di Xamarin.Forms Charles Petzold.
Nota
Le chiamate degli override di OnDisappearing
e OnAppearing
non possono essere considerate come indicazioni garantite dell'avvenuto spostamento tra le pagine. Ad esempio, in iOS l'override di OnDisappearing
viene chiamato per la pagina attiva quando l'applicazione viene terminata.
Prelievo di pagine dallo stack di navigazione
La pagina attiva può essere prelevata dallo stack di navigazione premendo il pulsante Indietro (fisico o su schermo) del dispositivo.
Per tornare a livello di codice alla pagina originale, l'istanza Page2Xaml
deve chiamare il metodo PopAsync
, come illustrato nell'esempio di codice seguente:
async void OnPreviousPageButtonClicked (object sender, EventArgs e)
{
await Navigation.PopAsync ();
}
Di conseguenza l'istanza Page2Xaml
viene rimossa dallo stack di navigazione e la nuova pagina in primo piano diventa la pagina attiva. Quando si richiama il metodo PopAsync
, si verificano gli eventi seguenti:
- Per la pagina che chiama
PopAsync
viene richiamato l'override diOnDisappearing
. - Per la pagina restituita viene richiamato l'override di
OnAppearing
. - L'attività
PopAsync
viene completata.
Tuttavia, l'ordine preciso in cui si verificano questi eventi è dipendente dalla piattaforma. Per altre informazioni, vedere il capitolo 24 del libro di Xamarin.Forms Charles Petzold.
Analogamente ai metodi PushAsync
e PopAsync
, la proprietà Navigation
di ogni pagina fornisce anche un metodo PopToRootAsync
, che viene visualizzato nell'esempio di codice seguente:
async void OnRootPageButtonClicked (object sender, EventArgs e)
{
await Navigation.PopToRootAsync ();
}
Questo metodo preleva tutto tranne la radice Page
dallo stack di navigazione, rendendo pertanto la pagina radice dell'applicazione la pagina attiva.
Animazione delle transizioni di pagina
La proprietà Navigation
di ogni pagina offre anche metodi di push e di prelievo sottoposti a override, che includono un parametro boolean
che controlla la visualizzazione di un'animazione di pagina durante gli spostamenti, come illustrato nell'esempio di codice seguente:
async void OnNextPageButtonClicked (object sender, EventArgs e)
{
// Page appearance not animated
await Navigation.PushAsync (new Page2Xaml (), false);
}
async void OnPreviousPageButtonClicked (object sender, EventArgs e)
{
// Page appearance not animated
await Navigation.PopAsync (false);
}
async void OnRootPageButtonClicked (object sender, EventArgs e)
{
// Page appearance not animated
await Navigation.PopToRootAsync (false);
}
L'impostazione del parametro boolean
su false
disabilita l'animazione per la transizione di pagina, mentre l'impostazione del parametro su true
abilita l'animazione per la transizione di pagina, a condizione che sia supportata dalla piattaforma sottostante. Tuttavia, i metodi di push e prelievo senza questo parametro abilitano l'animazione per impostazione predefinita.
Passaggio di dati durante gli spostamenti
In alcuni casi, una pagina deve passare dati a un'altra pagina durante gli spostamenti. Due tecniche per questa operazione sono il passaggio dei dati tramite un costruttore di pagina e l'impostazione di BindingContext
della nuova pagina sui dati. Di seguito verranno descritti entrambi.
Passaggio dei dati tramite un costruttore di pagina
La tecnica più semplice per il passaggio di dati a un'altra pagina durante gli spostamenti è tramite un parametro del costruttore di pagina, come illustrato nell'esempio di codice seguente:
public App ()
{
MainPage = new NavigationPage (new MainPage (DateTime.Now.ToString ("u")));
}
Questo codice crea un'istanza di MainPage
, passando la data e l'ora correnti in formato ISO8601, di cui viene eseguito il wrapping in un'istanza della NavigationPage
.
L'istanza di MainPage
riceve i dati tramite un parametro del costruttore, come illustrato nell'esempio di codice seguente:
public MainPage (string date)
{
InitializeComponent ();
dateLabel.Text = date;
}
I dati vengono quindi visualizzati nella pagina impostando la proprietà Label.Text
, come illustrato negli screenshot seguenti:
Passaggio dei dati tramite BindingContext
Un approccio alternativo per passare dati a un'altra pagina durante gli spostamenti consiste nell'impostare BindingContext
della nuova pagina sui dati, come illustrato nell'esempio di codice seguente:
async void OnNavigateButtonClicked (object sender, EventArgs e)
{
var contact = new Contact {
Name = "Jane Doe",
Age = 30,
Occupation = "Developer",
Country = "USA"
};
var secondPage = new SecondPage ();
secondPage.BindingContext = contact;
await Navigation.PushAsync (secondPage);
}
Questo codice imposta BindingContext
dell'istanza di SecondPage
sull'istanza di Contact
e quindi passa a SecondPage
.
SecondPage
usa quindi il data binding per visualizzare i dati dell'istanza di Contact
, come illustrato nell'esempio di codice XAML seguente:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PassingData.SecondPage"
Title="Second Page">
<ContentPage.Content>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Label Text="Name:" HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
</StackLayout>
...
<Button x:Name="navigateButton" Text="Previous Page" Clicked="OnNavigateButtonClicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
L'esempio di codice seguente illustra come è possibile implementare il data binding in C#:
public class SecondPageCS : ContentPage
{
public SecondPageCS ()
{
var nameLabel = new Label {
FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
FontAttributes = FontAttributes.Bold
};
nameLabel.SetBinding (Label.TextProperty, "Name");
...
var navigateButton = new Button { Text = "Previous Page" };
navigateButton.Clicked += OnNavigateButtonClicked;
Content = new StackLayout {
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
Children = {
new StackLayout {
Orientation = StackOrientation.Horizontal,
Children = {
new Label{ Text = "Name:", FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)), HorizontalOptions = LayoutOptions.FillAndExpand },
nameLabel
}
},
...
navigateButton
}
};
}
async void OnNavigateButtonClicked (object sender, EventArgs e)
{
await Navigation.PopAsync ();
}
}
I dati vengono quindi visualizzati nella pagina tramite una serie di controlli Label
, come illustrato negli screenshot seguenti:
Per altre informazioni sul data binding, vedere Data Binding Basics (Nozioni di base sul data binding).
Modifica dello stack di navigazione
La proprietà Navigation
espone una proprietà NavigationStack
dalla quale è possibile ottenere le pagine nello stack di navigazione. Mentre Xamarin.Forms mantiene l'accesso allo stack di navigazione, la Navigation
proprietà fornisce i InsertPageBefore
metodi e RemovePage
per la modifica dello stack inserendo pagine o rimuovendole.
Il metodo InsertPageBefore
inserisce una pagina specificata nello stack di navigazione prima di una pagina specificata esistente, come illustrato nel diagramma seguente:
Il metodo RemovePage
rimuove la pagina specificata dallo stack di navigazione, come illustrato nel diagramma seguente:
Questi metodi consentono un'esperienza di navigazione personalizzata, come la sostituzione di una pagina di accesso con una nuova pagina, dopo un accesso con esito positivo. Nell'esempio di codice seguente viene illustrato questo scenario:
async void OnLoginButtonClicked (object sender, EventArgs e)
{
...
var isValid = AreCredentialsCorrect (user);
if (isValid) {
App.IsUserLoggedIn = true;
Navigation.InsertPageBefore (new MainPage (), this);
await Navigation.PopAsync ();
} else {
// Login failed
}
}
A condizione che le credenziali dell'utente siano corrette, l'istanza di MainPage
viene inserita nello stack di navigazione prima della pagina corrente. Il metodo PopAsync
rimuove quindi la pagina corrente dallo stack di navigazione e l'istanza di MainPage
diventa la pagina attiva.
Visualizzazione delle viste nella barra di spostamento
Qualsiasi Xamarin.FormsView
oggetto può essere visualizzato nella barra di spostamento di un oggetto NavigationPage
. Questa operazione viene eseguita impostando la proprietà associata NavigationPage.TitleView
su una View
. Questa proprietà associata può essere impostata su qualunque Page
e quando viene eseguito il push della Page
in una NavigationPage
, NavigationPage
rispetta il valore della proprietà.
L'esempio seguente illustra come impostare la NavigationPage.TitleView
proprietà associata da XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="NavigationPageTitleView.TitleViewPage">
<NavigationPage.TitleView>
<Slider HeightRequest="44" WidthRequest="300" />
</NavigationPage.TitleView>
...
</ContentPage>
Questo è il codice C# equivalente:
public class TitleViewPage : ContentPage
{
public TitleViewPage()
{
var titleView = new Slider { HeightRequest = 44, WidthRequest = 300 };
NavigationPage.SetTitleView(this, titleView);
...
}
}
Il risultato è la visualizzazione di Slider
nella barra di spostamento sulla NavigationPage
:
Importante
Molte viste non saranno più visualizzate nella barra di spostamento, a meno che non vengano specificate le dimensioni della vista con le proprietà WidthRequest
e HeightRequest
. In alternativa, può essere eseguito il wrapping della vista in un StackLayout
con le proprietà HorizontalOptions
e VerticalOptions
impostate sui valori appropriati.
Si noti che, poiché la classe Layout
deriva dalla classe View
, la proprietà associata TitleView
può essere impostata per visualizzare una classe di layout contenente viste multiple. In iOS e nella piattaforma UWP (Universal Windows Platform) non è possibile modificare l'altezza della barra di navigazione, pertanto verrà effettuato il ritaglio se la vista visualizzata nella barra di spostamento sarà superiore alle dimensioni predefinite della barra di spostamento. Tuttavia, in Android, l'altezza della barra di spostamento può essere modificata impostando la proprietà associabile NavigationPage.BarHeight
per una double
che rappresenta la nuova altezza. Per altre informazioni, vedere Setting the Navigation Bar Height on a NavigationPage (Impostazione dell'altezza della barra di spostamento su una NavigationPage).
In alternativa, può essere suggerita una barra di spostamento estesa inserendo alcuni contenuti nella barra di spostamento e altri in una vista nella parte superiore del contenuto della pagina, da associare ai colori della barra di navigazione. Inoltre, in iOS la linea di separazione e l'ombreggiatura nella parte inferiore della barra di spostamento possono essere rimosse impostando la proprietà associabile NavigationPage.HideNavigationBarSeparator
su true
. Per altre informazioni, vedere Hiding the Navigation Bar Separator on a NavigationPage (Nascondere il separatore della barra di spostamento su una NavigationPage).
Nota
Le proprietà BackButtonTitle
, Title
, TitleIcon
e TitleView
possono definire tutte i valori che occupano spazio nella barra di spostamento. Mentre le dimensioni della barra di spostamento variano a seconda della piattaforma e delle dimensioni dello schermo, l'impostazione di tutte queste proprietà provocherà conflitti a causa dello spazio limitato disponibile. Invece di tentare di usare una combinazione di queste proprietà, è possibile ottenere un design migliore della barra di spostamento desiderata impostando solo la proprietà TitleView
.
Limiti
Esistono alcune limitazioni da tenere presenti quando si visualizza una View
nella barra di spostamento di una NavigationPage
:
- In iOS, le viste poste nella barra di spostamento di una
NavigationPage
vengono visualizzate in una posizione diversa a seconda se sono abilitati i titoli di grandi dimensioni. Per altre informazioni sull'abilitazione di titoli di grandi dimensioni, vedere Displaying Large Titles (Visualizzazione di titoli di grandi dimensioni). - In Android, il posizionamento delle viste nella barra di spostamento di una
NavigationPage
può essere eseguito solo nelle app che usano la compatibilità delle app. - Non è consigliabile posizionare viste grandi e complesse, come
ListView
eTableView
, nella barra di spostamento di unaNavigationPage
.