Navigation hiérarchique

Télécharger l’exemple Télécharger l’exemple

La classe NavigationPage propose une expérience de navigation hiérarchique où l’utilisateur est en mesure de parcourir les pages, vers l’avant et vers l’arrière, comme il le souhaite. La classe implémente la navigation sous forme de pile LIFO (dernier entré, premier sorti) d’objets Pages. Cet article montre comment utiliser la classe NavigationPage pour effectuer la navigation dans une pile de pages.

Pour passer d’une page à une autre, une application envoie une nouvelle page dans la pile de navigation, où elle devient la page active, comme illustré dans le diagramme suivant :

Envoi (push) d’une page vers la pile de navigation

Pour revenir à la page précédente, l’application dépile la page actuelle, et la nouvelle page tout en haut devient la page active, comme illustré dans le diagramme suivant :

Faire éclater une page à partir de la pile de navigation

Les méthodes de navigation sont exposées par la propriété Navigation sur n’importe quel type dérivé Page. Ces méthodes permettent d’envoyer des pages dans la pile de navigation, de retirer des pages de la pile de navigation, et d’effectuer des manipulations de la pile.

Navigation

Dans la navigation hiérarchique, la classe NavigationPage est utilisée pour parcourir une pile d’objets ContentPage. Les captures d’écran suivantes montrent les principaux composants de NavigationPage sur chaque plateforme :

Composants NavigationPage

La disposition d’une NavigationPage dépend de la plateforme :

  • Sur iOS, une barre de navigation est présente en haut de la page et affiche un titre, avec un bouton Précédent permettant de revenir à la page précédente.
  • Sur Android, une barre de navigation est présente en haut de la page et affiche un titre, une icône et un bouton Précédent permettant de revenir à la page précédente. L’icône est définie dans l’attribut [Activity] qui décore la classe MainActivity dans le projet propre à la plateforme Android.
  • Sur la plateforme Windows universelle, une barre de navigation en haut de la page affiche un titre.

Sur toutes les plateformes, la valeur de la propriété Page.Title est affichée en tant que titre de la page. En outre, la IconColor propriété peut être définie sur un Color qui est appliqué à l’icône dans la barre de navigation.

Notes

Nous vous recommandons de remplir une NavigationPage uniquement avec des instances de ContentPage.

Création de la page racine

La première page ajoutée à une pile de navigation est appelée la page racine de l’application et l’exemple de code suivant illustre le déroulement de l’opération :

public App ()
{
  MainPage = new NavigationPage (new Page1Xaml ());
}

L’instance de ContentPagePage1Xaml est ainsi envoyée dans la pile de navigation, où elle devient la page active et la page racine de l’application. Ceci est illustré dans les captures d’écran suivantes :

Page racine de la pile de navigation

Notes

La propriété RootPage d’une instance de NavigationPage permet d’accéder à la première page de la pile de navigation.

Envoi de pages dans la pile de navigation

Pour accéder à Page2Xaml, vous devez appeler la méthode PushAsync sur la propriété Navigation de la page active, comme illustré dans l’exemple de code suivant :

async void OnNextPageButtonClicked (object sender, EventArgs e)
{
  await Navigation.PushAsync (new Page2Xaml ());
}

L’instance de Page2Xaml est ainsi envoyée dans la pile de navigation, où elle devient la page active. Ceci est illustré dans les captures d’écran suivantes :

Page poussée vers la pile de navigation

Quand la méthode PushAsync est appelée, les événements suivants se produisent :

  • Pour la page qui appelle PushAsync, la substitution de OnDisappearing est appelée.
  • La substitution OnAppearing de la page cible de la navigation est appelée.
  • La tâche PushAsync est terminée.

Toutefois, l’ordre exact dans lequel ces événements se produisent dépend de la plateforme. Pour plus d’informations, consultez le chapitre 24 du livre de Xamarin.Forms Charles Petzold.

Notes

Les appels des substitutions OnDisappearing et OnAppearing ne peuvent pas être considérés comme des indications garanties de la navigation entre les pages. Par exemple, sur iOS, la substitution OnDisappearing est appelée sur la page active quand l’application se ferme.

Retrait de pages de la pile de navigation

La page active peut être retirée de la pile de navigation en appuyant sur le bouton Précédent sur l’appareil, qu’il s’agisse d’un bouton physique sur l’appareil ou d’un bouton à l’écran.

Pour revenir par programmation à la page d’origine, l’instance de Page2Xaml doit appeler la méthode PopAsync, comme illustré dans l’exemple de code suivant :

async void OnPreviousPageButtonClicked (object sender, EventArgs e)
{
  await Navigation.PopAsync ();
}

L’instance de Page2Xaml est ainsi retirée de la pile de navigation, et la nouvelle page tout en haut devient la page active. Quand la méthode PopAsync est appelée, les événements suivants se produisent :

  • Pour la page qui appelle PopAsync, la substitution de OnDisappearing est appelée.
  • La substitution OnAppearing de la page cible de la navigation est appelée.
  • La tâche PopAsync est terminée.

Toutefois, l’ordre exact dans lequel ces événements se produisent dépend de la plateforme. Pour plus d’informations, consultez le chapitre 24 du livre de Xamarin.Forms Charles Petzold.

En plus des méthodes PushAsync et PopAsync, la propriété Navigation de chaque page fournit également une méthode PopToRootAsync, illustrée dans l’exemple de code suivant :

async void OnRootPageButtonClicked (object sender, EventArgs e)
{
  await Navigation.PopToRootAsync ();
}

Cette méthode retire de la pile de navigation toutes les pages sauf la Page racine, ce qui fait de la page racine de l’application la page active.

Animation des transitions de page

La propriété Navigation de chaque page fournit également des méthodes d’envoi et de dépilation substituées qui incluent un paramètre boolean contrôlant l’affichage d’une animation de page durant la navigation, comme indiqué dans l’exemple de code suivant :

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);
}

Si vous affectez au paramètre boolean la valeur false, l’animation de transition de page est désactivée. En revanche, si vous affectez au paramètre la valeur true l’animation de transition de page est activée, à condition qu’elle soit prise en charge par la plateforme sous-jacente. Toutefois, les méthodes d’envoi et de dépilation qui n’ont pas ce paramètre activent l’animation par défaut.

Passage des données durant la navigation

Il est parfois nécessaire pour une page de transmettre des données à une autre page lors de la navigation. Il existe pour cela deux techniques : transmettre les données par le biais d’un constructeur de page, et définir les données comme BindingContext de la nouvelle page. Nous allons maintenant examiner chacune de ces techniques.

Passage des données via un constructeur de page

La technique la plus simple pour passer des données à une autre page durant la navigation consiste à utiliser un paramètre de constructeur de page, comme indiqué dans l’exemple de code suivant :

public App ()
{
  MainPage = new NavigationPage (new MainPage (DateTime.Now.ToString ("u")));
}

Ce code crée une instance de MainPage et transmet la date et l’heure actuelles au format ISO8601, encapsulées dans une instance de NavigationPage.

L’instance de MainPage reçoit les données via un paramètre de constructeur, comme indiqué dans l’exemple de code suivant :

public MainPage (string date)
{
  InitializeComponent ();
  dateLabel.Text = date;
}

Les données sont ensuite affichées dans la page en définissant la propriété Label.Text, comme indiqué dans les captures d’écran suivantes :

Données transmises via un constructeur de page

Passage des données via un BindingContext

Il existe une autre approche pour passer des données à une autre page durant la navigation. Elle consiste à affecter les données au BindingContext de la nouvelle page, comme indiqué dans l’exemple de code suivant :

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);
}

Ce code affecte au BindingContext de l’instanceSecondPage l’instance de Contact, puis accède à SecondPage.

SecondPage utilise ensuite la liaison de données pour afficher les données de l’instance de Contact, comme indiqué dans l’exemple de code XAML suivant :

<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’exemple de code suivant montre comment effectuer la liaison de données en 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 ();
  }
}

Les données sont ensuite affichées dans la page par une série de contrôles Label, comme indiqué dans les captures d’écran suivantes :

Données transmises via un BindingContext

Pour plus d’informations sur la liaison de données, consultez Notions de base de la liaison de données.

Manipulation de la pile de navigation

La propriété Navigation expose une propriété NavigationStack à partir de laquelle les pages dans la pile de navigation peuvent être obtenues. Tout en Xamarin.Forms conservant l’accès à la pile de navigation, la Navigation propriété fournit les InsertPageBefore méthodes et RemovePage pour manipuler la pile en insérant des pages ou en les supprimant.

La méthode InsertPageBefore insère une page spécifiée dans la pile de navigation avant une page existante spécifiée, comme indiqué dans le diagramme suivant :

Insertion d’une page dans la pile de navigation

La méthode RemovePage supprime la page spécifiée de la pile de navigation, comme illustré dans le diagramme suivant :

Suppression d’une page de la pile de navigation

Ces méthodes permettent de disposer d’une expérience de navigation personnalisée, par exemple remplacer une page de connexion par une nouvelle page, suite à une connexion réussie. L’exemple de code suivant illustre ce scénario :

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
  }
}

À condition que les informations d’identification de l’utilisateur soient correctes, l’instance de MainPage est insérée dans la pile de navigation avant la page active. La méthode PopAsync supprime ensuite la page active de la pile de navigation, et l’instance de MainPage devient la page active.

Affichage des vues dans la barre de navigation

Tout Xamarin.FormsView peut être affiché dans la barre de navigation d’un NavigationPage. Pour cela, vous devez définir la propriété jointe NavigationPage.TitleView sur une View. Cette propriété jointe peut être définie sur n’importe quelle Page, et quand la Page envoyée vers sur une NavigationPage, la NavigationPage respecte la valeur de la propriété.

L’exemple suivant, tiré de l’exemple Title View, montre comment définir la propriété jointe NavigationPage.TitleView à partir de 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>

Voici le code C# équivalent :

public class TitleViewPage : ContentPage
{
    public TitleViewPage()
    {
        var titleView = new Slider { HeightRequest = 44, WidthRequest = 300 };
        NavigationPage.SetTitleView(this, titleView);
        ...
    }
}

Il en résulte l’affichage d’un Slider dans la barre de navigation dans la NavigationPage :

le titre du curseurAfficher

Important

De nombreuses vues n’apparaissent dans la barre de navigation que si la taille de la vue est spécifiée avec les propriétés WidthRequest et HeightRequest. En guise d’alternative, vous pouvez encapsuler la vue dans un StackLayout avec des valeurs appropriées affectées aux propriétés HorizontalOptions et VerticalOptions.

Notez que, étant donné que la classe Layout dérive de la classe View, la propriété jointe TitleView peut être configurée de façon à afficher une classe de disposition qui contient plusieurs vues. Sur iOS et la plateforme universelle Windows (UWP), la hauteur de la barre de navigation ne peut pas être changée ; ainsi, un découpage se produira si la taille de la vue affichée dans la barre de navigation est supérieure à la taille par défaut de la barre de navigation. En revanche, sur Android, la hauteur de la barre de navigation peut être changée en affectant un représentant la nouvelle hauteur comme valeur de la propriété pouvant être liée NavigationPage.BarHeightdouble. Pour plus d’informations, consultez Définition de la hauteur de la barre de navigation sur une NavigationPage.

En guise d’alternative, une barre de navigation étendue peut être suggérée en plaçant une partie du contenu dans la barre de navigation et une autre partie dans une vue en haut du contenu de page, à laquelle vous affectez une couleur correspondant à celle de la barre de navigation. En outre, sur iOS la ligne de séparation et l’ombre qui se trouve au bas de la barre de navigation peuvent être supprimées en affectant la valeur à la propriété pouvant être liée NavigationPage.HideNavigationBarSeparatortrue. Pour plus d’informations, consultez Masquage du séparateur de barre de navigation sur une NavigationPage.

Notes

Les BackButtonTitlepropriétés , Title, TitleIconet TitleView peuvent toutes définir des valeurs qui occupent de l’espace dans la barre de navigation. Bien que la taille de la barre de navigation varie en fonction de la plateforme et de la taille de l’écran, la définition de toutes ces propriétés provoquera des conflits en raison de l’espace limité disponible. Au lieu d’essayer d’utiliser une combinaison de ces propriétés, vous obtiendrez peut-être plus facilement la conception de barre de navigation souhaitée en définissant uniquement la propriété TitleView.

Limites

Vous devez prendre en compte un certain nombre de limitations lors de l’affichage d’une View dans la barre de navigation d’une NavigationPage :

  • Sur iOS, les vues placées dans la barre de navigation d’une NavigationPage apparaissent dans une position différente selon que les grands titres sont activés ou non. Pour plus d’informations sur l’activation des grands titres, consultez Affichage de grands titres.
  • Sur Android, vous ne pouvez placer des vues dans la barre de navigation d’une NavigationPage que dans les applications qui utilisent app-compat.
  • Nous vous déconseillons de placer des vues volumineuses et complexes, telles que ListView et TableView, dans la barre de navigation d’une NavigationPage.