2017/8/28

Xamarin.Forms 教學系列文(二十四.壹)Page Navigation - 頁面導覽


學習目標
  • Navigation 頁面導覽
  • 導覽的頁面類型 Modaless & ModalPage
  • Navigation 的一些屬性

頁面導覽 在資訊界其實很常見,例如你正在看這篇教學所使用的瀏覽器,那左上角的上一頁,就是一種頁面導覽。

如果讓我們以程式的觀點來看待 頁面導覽 ,其實就是 實作堆疊(Stack)

當有新頁面出現時,就將此頁面 Push 進 Stack 並顯示他,
當要回到前一頁時,就 Pop 掉 Stack 第一筆,並顯示最上面一筆的頁面,

而這也是 Xamarin.Forms 實作 Navigation 的方法,
所以會看到 Navigation 類別提供了 Push Pop 的方法,甚至可以手動取得 Navigation Stack 來做進一步處理

導覽架構內一定有初始頁,我們通常稱作 Main page、Home page 或是 Start page。

而從 Main page 準備導覽時,下一頁的類型我們有兩種可以選擇:
  • Modeless page (有返回鈕) - 其實也就是正常的導覽頁面
  • Modal page (無返回鈕)

我們會從 Navigation 類別所提供的方法來做介紹,並用範例讓大家了解這兩種頁面類型的差異。 

Modeless & Modal 頁面

Navigation 提供兩種方法導覽至下一頁
  • Task PushAsync(Page page)
  • Task PushModalAsync(Page page)

返回也定義了兩個方法 (手動做返回時會寫)
  • Task<Page> PopAsync()
  • Task<Page> PopModalAsync()

//這邊用了非同步的 Task ,但不代表導覽的頁面是在另一個 Thread 執行,後面的章節會來探討這一部分

Modeless  Modal 這兩種頁面類型最大的差別在於
有沒有自動提供返回的按鈕!

為什麼需要無返回鈕的 Modal 頁?
通常用於強制使用者執行完某件事、或輸入完某些資料後,最後才用 Pop 方法導回頁面。

來看範例,
範例包含了三個頁面程式,分別為 MainPage, ModalPage ModelessPage
我們會在 MainPage 內加入兩個 Button,分別導向其他兩頁:

MainPage
public class MainPage : ContentPage
{
    public MainPage()
    {
        Title = "Main Page";

        Button gotoModelessButton = new Button
        {
            Text = "Go to Modeless Page",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        //導覽至 ModelessPage
        gotoModelessButton.Clicked += async (sender, args) =>
        {
            await Navigation.PushAsync(new ModelessPage());
        };

        Button gotoModalButton = new Button
        {
            Text = "Go to Modal Page",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.CenterAndExpand
        };

        //導覽至 ModalPage
        gotoModalButton.Clicked += async (sender, args) => 
        {
            await Navigation.PushModalAsync(new ModalPage());
        };

        Content = new StackLayout
        {
            Children =
            {
                gotoModelessButton, gotoModalButton
            }
        };
    }
}

*非常重要如有用到 Navigation,App Class 的 MainPage 要改成這樣:
public class App : Application
{
    public App()
    {
        MainPage = new NavigationPage(new MainPage());
    } 
    …
 }

執行結果:
可以注意下 Title 設定的文字會出現在上方

接著點擊 Go to Modeless Page,會導向 ModelessPage
public class ModelessPage : ContentPage
{
    public ModelessPage()
    {
        Title = "Modeless Page";

        Button goBackButton = new Button
        {
            Text = "Back to Main",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        };

        goBackButton.Clicked += async (sender, args) =>
        {
            await Navigation.PopAsync();
        };

        Content = goBackButton;
    }
}

*你不一定要實作返回按鈕,Android 和 iOS 上方都已經有現成的返回鈕可以用了…
*Android 和 iOS 上方那一排稱作 Navigation bar

返回到 MainPage 後,讓我們點擊 Go to Modal Page:
public class ModalPage : ContentPage
{
    public ModalPage()
    {
        Title = "Modal Page";

        Button goBackButton = new Button
        {
            Text = "Back to Main",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        };

        goBackButton.Clicked += async (sender, args) =>
        {
            await Navigation.PopAsync();
        };

        Content = goBackButton;
    }
}

可以注意到 Modal 頁上方的 Navigation bar 不見了~ 連 Title 都沒出來~ 就是不會自動給返回鈕!


特別注意的規則,若要再次導覽時,:
  • Modeless page 可以再導向其他 Modeless 或 Modal 頁
  • Modal 只能再導到 Modal 頁

Navigation 的一些屬性

這邊介紹一些可以改變 Navigation bar 外觀的屬性,

例如設定背景色文字顏色
public class App : Application
{
    public App()
    {
        MainPage = new NavigationPage(new MainPage())
        {
            BarBackgroundColor = Color.Blue,
            BarTextColor = Color.Pink



除了在 App 內設定全域的屬性,

也可以在個別的 Page 內來做設定:

像是個別頁返回鈕消失
public class ModelessPage : ContentPage
{
    public ModelessPage()
    {
        Title = "Modeless Page";
        NavigationPage.SetHasBackButton(this, false);
        … 
    }
}

XAML 寫法
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="ModelessAndModal.ModelessPage" 
             Title="Modeless Page"
             NavigationPage.HasBackButton="False">
    …
</ContentPage>


還有其他屬性像是:

讓整條 bar 消失:
NavigationPage.SetHasNavigationBar(this, false);

設定返回鈕顯示的字:
NavigationPage.SetBackButtonTitle(this, "go back");

設定 Icon:
NavigationPage.SetTitleIcon(this, "ic_action_flash_on.png");


其實我一直很疑惑為什麼這本書要把 Navigation 放到 24 章,
在我學 Xamarin 的第一天起,我就一直很困惑要怎麼在 App 導向下一個頁面。

直到我讀到 24 章... 微軟你有想過 1 ~ 23 章很遙遠嗎...

好了抱怨完畢。


9 則留言:

  1. 請問一下,
    我在 Tabbed Page 裡做 page navigation,我的 tab bar會被蓋掉耶
    是有什麼地方要設定嗎??
    謝謝

    回覆刪除
    回覆
    1. 別理我,我解決了,雖然不是很確定改了什麼...
      謝謝

      刪除
    2. okok,正想問清楚問題哈哈

      刪除
  2. 想要問一下,若是返回上一頁,上一頁有辦法更新嗎?refresh之類的,感恩

    回覆刪除
    回覆
    1. 建議搭配 MVVM,在頁面 OnAppearing 時重新讀取資料

      刪除
  3. 像是個別頁返回"紐"消失

    回覆刪除
  4. 在ModelPage的goBackButton事件中我把PopAsync改成PopModalAsync,否則會報錯。
    請問這是為什麼?

    回覆刪除
    回覆
    1. 看你 push 了什麼頁面,就要 pop 那個型態的頁面。或是你也可以把錯誤訊息貼上來讓我看看

      刪除