Иерархическая навигацияHierarchical Navigation

Скачать пример Скачать примерDownload Sample Download the sample

Класс NavigationPage обеспечивает иерархическую навигацию, при которой пользователь может переходить по страницам вперед и назад по своему желанию. Этот класс реализует навигацию на основе стека объектов Page по методу ЛИФО (последним поступил — первым обслужен). В этой статье показано, как использовать класс NavigationPage для навигации в стеке страниц.The NavigationPage class provides a hierarchical navigation experience where the user is able to navigate through pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO) stack of Page objects. This article demonstrates how to use the NavigationPage class to perform navigation in a stack of pages.

Для перехода с одной страницы на другую приложение помещает новую страницу в стек навигации, где она становится активной страницей, как показано на следующем рисунке.To move from one page to another, an application will push a new page onto the navigation stack, where it will become the active page, as shown in the following diagram:

Для возврата к предыдущей странице приложение выбирает текущую страницу из стека навигации, после чего активной становится верхняя страница в стеке, как показано на следующем рисунке.To return back to the previous page, the application will pop the current page from the navigation stack, and the new topmost page becomes the active page, as shown in the following diagram:

Методы навигации предоставляются свойством Navigation любых типов, производных от класса Page.Navigation methods are exposed by the Navigation property on any Page derived types. Эти методы предоставляют возможность для отправки страниц в стек навигации, извлечения страниц из стека навигации, а также для выполнения операций со стеком.These methods provide the ability to push pages onto the navigation stack, to pop pages from the navigation stack, and to perform stack manipulation.

Выполнение навигацииPerforming Navigation

При иерархической навигации класс NavigationPage используется для перехода по стеку объектов ContentPage.In hierarchical navigation, the NavigationPage class is used to navigate through a stack of ContentPage objects. На следующих снимках экрана показаны основные компоненты NavigationPage на каждой платформе.The following screenshots show the main components of the NavigationPage on each platform:

Макет NavigationPage зависит от платформы:The layout of a NavigationPage is dependent on the platform:

  • В iOS панель навигации находится в верхней части страницы, где отображается заголовок и кнопка Назад, которая возвращает на предыдущую страницу.On iOS, a navigation bar is present at the top of the page that displays a title, and that has a Back button that returns to the previous page.
  • В Android панель навигации находится в верхней части страницы, где отображается заголовок, значок и кнопка Назад, которая возвращает на предыдущую страницу.On Android, a navigation bar is present at the top of the page that displays a title, an icon, and a Back button that returns to the previous page. Значок определяется в атрибуте [Activity], который оформляет класс MainActivity в проекте, зависящем от платформы Android.The icon is defined in the [Activity] attribute that decorates the MainActivity class in the Android platform-specific project.
  • На универсальной платформе Windows панель навигации расположена в верхней части страницы, где отображается заголовок.On the Universal Windows Platform, a navigation bar is present at the top of the page that displays a title.

На всех платформах значение свойства Page.Title отображается как заголовок страницы.On all the platforms, the value of the Page.Title property will be displayed as the page title.

Примечание

Рекомендуется заполнять NavigationPage только экземплярами ContentPage.It's recommended that a NavigationPage should be populated with ContentPage instances only.

Создание корневой страницыCreating the Root Page

Первая страница, добавленная в стек навигации, называется корневой страницей приложения, что демонстрируется в следующем примере кода:The first page added to a navigation stack is referred to as the root page of the application, and the following code example shows how this is accomplished:

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

В результате в стек навигации помещается экземпляр Page1Xaml ContentPage, где он становится активной страницей и корневой страницей приложения.This causes the Page1Xaml ContentPage instance to be pushed onto the navigation stack, where it becomes the active page and the root page of the application. Эти действия показаны на следующих снимках экрана.This is shown in the following screenshots:

Примечание

Свойство RootPage экземпляра NavigationPage предоставляет доступ к первой странице в стеке навигации.The RootPage property of a NavigationPage instance provides access to the first page in the navigation stack.

Помещение страниц в стек навигацииPushing Pages to the Navigation Stack

Для перехода к странице Page2Xaml необходимо вызвать метод PushAsync свойства Navigation текущей страницы, как показано в следующем примере кода.To navigate to Page2Xaml, it is necessary to invoke the PushAsync method on the Navigation property of the current page, as demonstrated in the following code example:

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

В результате в стек навигации помещается экземпляр Page2Xaml, где он становится активной страницей.This causes the Page2Xaml instance to be pushed onto the navigation stack, where it becomes the active page. Эти действия показаны на следующих снимках экрана.This is shown in the following screenshots:

Когда вызывается метод PushAsync, происходят следующие события.When the PushAsync method is invoked, the following events occur:

  • У страницы, вызывающей PushAsync, вызывается переопределение OnDisappearing.The page calling PushAsync has its OnDisappearing override invoked.
  • Вызывается переопределение OnAppearing страницы, к которой осуществляется переход.The page being navigated to has its OnAppearing override invoked.
  • Задача PushAsync завершается.The PushAsync task completes.

Однако точный порядок, в котором происходят эти события, зависит от платформы.However, the precise order in which these events occur is platform dependent. Дополнительные сведения см. в главе 24 книги Xamarin.Forms Чарльза Петцольда (Charles Petzold).For more information, see Chapter 24 of Charles Petzold's Xamarin.Forms book.

Примечание

Вызовы переопределений OnDisappearing и OnAppearing не могут рассматриваться как гарантия перехода на страницу.Calls to the OnDisappearing and OnAppearing overrides cannot be treated as guaranteed indications of page navigation. Например, в iOS переопределение OnDisappearing вызывается на активной странице, когда приложение завершает работу.For example, on iOS, the OnDisappearing override is called on the active page when the application terminates.

Извлечение страниц из стека навигацииPopping Pages from the Navigation Stack

Активная страница может быть извлечена из стека навигации путем нажатия кнопки Назад на устройстве, причем это может быть как физическая кнопка, так и кнопка на экране.The active page can be popped from the navigation stack by pressing the Back button on the device, regardless of whether this is a physical button on the device or an on-screen button.

Чтобы вернуться на исходную страницу программным образом, экземпляр Page2Xaml должен вызвать метод PopAsync, как показано в следующем примере кода:To programmatically return to the original page, the Page2Xaml instance must invoke the PopAsync method, as demonstrated in the following code example:

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

В результате экземпляр Page2Xaml удаляется из стека навигации, а активной становится верхняя страница в нем.This causes the Page2Xaml instance to be removed from the navigation stack, with the new topmost page becoming the active page. Когда вызывается метод PopAsync, происходят следующие события.When the PopAsync method is invoked, the following events occur:

  • У страницы, вызывающей PopAsync, вызывается переопределение OnDisappearing.The page calling PopAsync has its OnDisappearing override invoked.
  • У страницы, к которой вы возвращаетесь, вызывается переопределение OnAppearing.The page being returned to has its OnAppearing override invoked.
  • Возвращается задача PopAsync.The PopAsync task returns.

Однако точный порядок, в котором происходят эти события, зависит от платформы.However, the precise order in which these events occur is platform dependent. Дополнительные сведения см. в главе 24 книги Xamarin.Forms Чарльза Петцольда (Charles Petzold).For more information see Chapter 24 of Charles Petzold's Xamarin.Forms book.

Как и методы PushAsync и PopAsync, свойство Navigation каждой страницы также предоставляет метод PopToRootAsync, который показан в следующем примере кода.As well as PushAsync and PopAsync methods, the Navigation property of each page also provides a PopToRootAsync method, which is shown in the following code example:

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

Этот метод извлекает все, кроме корневого объекта Page, из стека навигации; таким образом, корневая страница приложения становится активной страницей.This method pops all but the root Page off the navigation stack, therefore making the root page of the application the active page.

Анимация переходов по страницамAnimating Page Transitions

Свойство Navigation каждой страницы также предоставляет переопределенные методы отправки и извлечения, которые включают параметр boolean, указывающий, нужно ли отображать анимацию страниц во время перехода, как показано в следующем примере кода.The Navigation property of each page also provides overridden push and pop methods that include a boolean parameter that controls whether to display a page animation during navigation, as shown in the following code example:

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

Установка для параметра boolean значения false отключает анимацию перехода страницы, а установка для параметра значения true включает анимацию, при условии что она поддерживается используемой платформой.Setting the boolean parameter to false disables the page-transition animation, while setting the parameter to true enables the page-transition animation, provided that it is supported by the underlying platform. Однако методы отправки и извлечения без этого параметра включают анимацию по умолчанию.However, the push and pop methods that lack this parameter enable the animation by default.

Передача данных при переходеPassing Data when Navigating

Иногда странице необходимо передать данные другой странице во время навигации.Sometimes it's necessary for a page to pass data to another page during navigation. Существует два способа: передача данных с помощью конструктора страниц и указание данных для объекта BindingContext новой страницы.Two techniques for accomplishing this are passing data through a page constructor, and by setting the new page's BindingContext to the data. Мы обсудим оба способа.Each will now be discussed in turn.

Передача данных через конструктор страницPassing Data through a Page Constructor

Самый простой способ передачи данных на другую страницу во время навигации — в качестве параметра конструктора страниц, как показано в следующем примере кода.The simplest technique for passing data to another page during navigation is through a page constructor parameter, which is shown in the following code example:

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

Этот код создает экземпляр MainPage, передавая текущую дату и время в формате ISO8601, который упаковывается в экземпляр NavigationPage.This code creates a MainPage instance, passing in the current date and time in ISO8601 format, which is wrapped in a NavigationPage instance.

Экземпляр MainPage получает данные с помощью параметра конструктора, как показано в следующем примере кода.The MainPage instance receives the data through a constructor parameter, as shown in the following code example:

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

Данные отображаются на странице путем установки свойства Label.Text, как показано на следующих снимках экрана.The data is then displayed on the page by setting the Label.Text property, as shown in the following screenshots:

Передача данных через объект BindingContextPassing Data through a BindingContext

Альтернативный способ передачи данных на другую страницу во время навигации —указание данных для объекта BindingContext новой страницы, как показано в следующем примере кода:An alternative approach for passing data to another page during navigation is by setting the new page's BindingContext to the data, as shown in the following code example:

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

Этот код задает объекту BindingContext экземпляра SecondPage экземпляр Contact, а затем переходит к SecondPage.This code sets the BindingContext of the SecondPage instance to the Contact instance, and then navigates to the SecondPage.

Затем SecondPage использует привязку данных для отображения данных экземпляра Contact, как показано в следующем примере кода XAML.The SecondPage then uses data binding to display the Contact instance data, as shown in the following XAML code example:

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

В следующем примере кода показано, как можно выполнить привязку данных в C#.The following code example shows how the data binding can be accomplished 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 ();
  }
}

Данные отображаются на странице с помощью нескольких элементов управления Label, как показано на следующих снимках экрана.The data is then displayed on the page by a series of Label controls, as shown in the following screenshots:

Дополнительные сведения о привязке данных см. в статье Основы привязки данных.For more information about data binding, see Data Binding Basics.

Управление стеком навигацииManipulating the Navigation Stack

Свойство Navigation предоставляет свойство NavigationStack, из которого могут быть получены страницы в стеке навигации.The Navigation property exposes a NavigationStack property from which the pages in the navigation stack can be obtained. Хотя Xamarin.Forms поддерживает доступ к стеку навигации, свойство Navigation предоставляет методы InsertPageBefore и RemovePage для управления стеком путем вставки страниц или их удаления.While Xamarin.Forms maintains access to the navigation stack, the Navigation property provides the InsertPageBefore and RemovePage methods for manipulating the stack by inserting pages or removing them.

Метод InsertPageBefore вставляет указанную страницу в стек навигации перед указанной существующей страницей, как показано на следующей схеме.The InsertPageBefore method inserts a specified page in the navigation stack before an existing specified page, as shown in the following diagram:

Метод RemovePage удаляет указанную страницу из стека навигации, как показано на следующей схеме.The RemovePage method removes the specified page from the navigation stack, as shown in the following diagram:

Эти методы обеспечивают возможность настраиваемой навигации, например замены страницы входа на новую страницу после успешного входа.These methods enable a custom navigation experience, such as replacing a login page with a new page, following a successful login. Следующий пример кода демонстрирует этот сценарий.The following code example demonstrates this 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
  }
}

При условии что учетные данные пользователя верны, экземпляр MainPage вставляется в стек навигации перед текущей страницей.Provided that the user's credentials are correct, the MainPage instance is inserted into the navigation stack before the current page. Метод PopAsync удаляет текущую страницу из стека навигации, а активной страницей становится экземпляр MainPage.The PopAsync method then removes the current page from the navigation stack, with the MainPage instance becoming the active page.

Отображение представлений на панели навигацииDisplaying Views in the Navigation Bar

Любое представление Xamarin.Forms View может отображаться на панели навигации NavigationPage.Any Xamarin.Forms View can be displayed in the navigation bar of a NavigationPage. Для этого нужно установить присоединенное свойство NavigationPage.TitleView в View.This is accomplished by setting the NavigationPage.TitleView attached property to a View. Это присоединенное свойство может быть задано для любого объекта Page, и, когда Page помещается в NavigationPage, NavigationPage будет учитывать значение этого свойства.This attached property can be set on any Page, and when the Page is pushed onto a NavigationPage, the NavigationPage will respect the value of the property.

В следующем примере, взятом из примера представления заголовка, показано, как задать присоединенное свойство NavigationPage.TitleView в XAML.The following example, taken from the Title View sample, shows how to set the NavigationPage.TitleView attached property from 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>

Вот эквивалент в коде C#:Here is the equivalent C# code:

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

В результате объект Slider отображается на панели навигации на NavigationPage:This results in a Slider being displayed in the navigation bar on the NavigationPage:

Представление заголовка ползункаSlider TitleView

Важно!

Многие представления не будут отображаться на панели навигации, если не указан размер представления с помощью свойств WidthRequest и HeightRequest.Many views won't appear in the navigation bar unless the size of the view is specified with the WidthRequest and HeightRequest properties. Кроме того, представление может быть заключено в StackLayout со свойствами HorizontalOptions и VerticalOptions, для которых установлены соответствующие значения.Alternatively, the view can be wrapped in a StackLayout with the HorizontalOptions and VerticalOptions properties set to appropriate values.

Поскольку класс Layout является производным от класса View, присоединенное свойство TitleView можно настроить для отображения класса макета, содержащего несколько представлений.Note that, because the Layout class derives from the View class, the TitleView attached property can be set to display a layout class that contains multiple views. В iOS и на универсальной платформе Windows (UWP) высоту панели навигации нельзя изменить, поэтому она будет обрезана, если представление, отображаемое на панели навигации, больше, чем размер панели навигации по умолчанию.On iOS and the Universal Windows Platform (UWP), the height of the navigation bar can't be changed, and so clipping will occur if the view displayed in the navigation bar is larger than the default size of the navigation bar. В Android высоту панели навигации можно изменить, задав для привязываемого свойства NavigationPage.BarHeight значение double, представляющее новую высоту.However, on Android, the height of the navigation bar can be changed by setting the NavigationPage.BarHeight bindable property to a double representing the new height. Дополнительные сведения см. в разделе Установка высоты панели навигации в объекте NavigationPage.For more information, see Setting the Navigation Bar Height on a NavigationPage.

Также панель навигации можно расширить, если поместить некоторое содержимое на панели навигации, а некоторое — в представление в верхней части страницы таким образом, чтобы цвет совпадал с панелью навигации.Alternatively, an extended navigation bar can be suggested by placing some of the content in the navigation bar, and some in a view at the top of the page content that you color match to the navigation bar. Кроме того, в iOS разделительную линию и тень в нижней части панели навигации можно удалить, установив для привязываемого свойства NavigationPage.HideNavigationBarSeparator значение true.In addition, on iOS the separator line and shadow that's at the bottom of the navigation bar can be removed by setting the NavigationPage.HideNavigationBarSeparator bindable property to true. Дополнительные сведения см. в разделе Сокрытие разделителя панели навигации в объекте NavigationPage.For more information, see Hiding the Navigation Bar Separator on a NavigationPage.

Примечание

Свойства BackButtonTitle, Title, TitleIcon и TitleView позволяют определять значения, которые занимают место на панели навигации.The BackButtonTitle, Title, TitleIcon, and TitleView properties can all define values that occupy space on the navigation bar. Хотя размер панели навигации зависит от платформы и размера экрана, установка всех этих свойств приведет к конфликтам из-за ограничений свободного пространства.While the navigation bar size varies by platform and screen size, setting all of these properties will result in conflicts due to the limited space available. Вместо комбинации этих свойств лучше задать желаемый дизайн панели навигации только с помощью свойства TitleView.Instead of attempting to use a combination of these properties, you may find that you can better achieve your desired navigation bar design by only setting the TitleView property.

ОграниченияLimitations

Существует ряд ограничений, которые следует учитывать при отображении объекта View на панели навигации NavigationPage.There are a number of limitations to be aware of when displaying a View in the navigation bar of a NavigationPage:

  • В iOS представления, размещенные на панели навигации NavigationPage, отображаются по-разному в зависимости от того, включены ли крупные заголовки.On iOS, views placed in the navigation bar of a NavigationPage appear in a different position depending on whether large titles are enabled. Дополнительные сведения о включении крупных заголовков см. в разделе Отображение крупных заголовков.For more information about enabling large titles, see Displaying Large Titles.
  • В Android можно поместить представления на панели навигации NavigationPage только в приложениях, использующих совместимость приложений.On Android, placing views in the navigation bar of a NavigationPage can only be accomplished in apps that use app-compat.
  • Не рекомендуется помещать большие и сложные представления, например ListView и TableView, в строке навигации NavigationPage.It's not recommended to place large and complex views, such as ListView and TableView, in the navigation bar of a NavigationPage.