在從事 Xamarin.Forms 教學經驗中,有許多人都在詢問要如何設計出具有 TabbedPage 標籤式頁面 功能,不過,因為我個人比較少使用這個頁面,通常遇到這樣的視覺需求,我都是自行設計使用者控制向來完成這樣的需求,因此,在這篇文章中,我們將要來體驗 TabbedPage 標籤式頁面在 Xamarin.Forms 中要如何使用?不過,我們在這裡所練習的架構,是採用 Prism 框架下的 MVVM 設計模式,並且需要使用到 Prism7 的版本才能夠時做出來。
這篇文章所提到的所有專案原始碼,可以從 這裡 取得
在我們的練習情境之中,我們需要設計一個應用程式的首頁為 TabbedPage 標籤式頁面,在這個 TabbedPage 標籤式頁面中,共會存在四個標籤 (在 Prism7 中,我們可以使用這個查詢字串
createTab
來完成宣告,這個標籤頁面總共需要有多少個頁面存在),不過,我們需要指定第三個標籤頁面為我們預設顯示的頁面,底下為我們實際執行後的螢幕截圖,預設顯示第三頁面內容 (在 Prism7 中,我們可以使用這個查詢字串 selectedTab
來指定預設顯示的頁次是哪個)。
另外,我們希望切換到第二個標籤頁面的時候,他是具有導航工具列的效果,也就是說,我們切換到第二頁的時候,在第二頁內會有一個按鈕,按下這個按鈕之後,將會導航到另外一個新的頁面,在此同時,螢幕上會有導航工具列出現,如同下圖:
不過,若我們沒有使用 Prism7 所提供的標籤頁面之特定查詢字串,此時,我們將會變成這樣的情境,這樣的結果將不是我們所期望需要的。
接下來,我們來實際練習開發出這樣的應用。
建立練習專案
- 首先,我們使用 Prism Template Pack (現在使用的 2.0.9 版本)建立起一個 Xamarin.Forms 開發專案
- 我們需要建立一個 TabbedPage 頁面,我們把它命名為 MainTabbedPage,在這個頁面 View 與頁面檢視 ViewModel 中,我們不需要做任何特別處理。
- 另外,因為我們需要有許多標籤頁次需要顯示,因此,我們需要建立出五個 ContentPage,所以,我們產生出五個 ContentPage,分別名稱為 Page1, Page2, Page3, Page4, Page21。
- 接下來,我們需要分別將這五個 ContentPage 的 View 和 ViewModel 進行設計
- 最後,我們需要修正 Xamarin.Forms 專案的進入點 ( Entry Point ),也就是 App.xaml.cs 檔案,我們將其打開,在 OnInitialized 方法內,將 await NavigationService.NavigateAsync 方法內需要的引數,修改成為
MainTabbedPage?createTab=Page1&createTab=NavigationPage|Page2&createTab=Page3&createTab=Page4&selectedTab=Page3
在這裡,我們透過了查詢字串中createTab
這個參數,指定這個標籤式頁面需要那些 ContentPage,由於我們在這個練習中,總共需要用到四個標籤頁面,所以,我們在查詢字串中,總共需要使用到四次的createTab
。其中,您將會看到在第二個createTab
中,其設定值似乎與其他的不太一樣,在這裡,我們需要在頁面2中,提供導航到其他頁面的機制,因此,我們需要在createTab
參數名稱之後,先使用 NavigationPage 緊接著使用管道|
字元,最後再加上 Page2,這表示了,第二個標籤頁面中,將會顯示出具有導航工具列的效果。而在頁面2中,我們放置了一個按鈕,當您按下這個按鈕之後,將會導航到 Page21 這個頁面,底下是我們所期望呈現的結果。我們可以看到,最上方會出現導航工具列,並且會有回上頁的按鈕出現,不過,新的頁面還是出現在 TabbedPage 標籤式頁面的第二個頁次中。若您的專案需要不想要做到這樣的結果,您可以參考頁面1的設計,在這個頁面中,我們放置了一個按鈕,按下這個按鈕,就一樣會導航到 Page21,不過,當您切換到 頁面1 頁次的時候,看到的是如下螢幕截圖,他與頁面2 的內容完全不一樣,您知道為什麼會有這樣的結果嗎?當我們在頁面1點選了這個按鈕,此時,將會出現如下圖內容。
MainTabbedPage 的 View 內容
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XFTabbed2.Views.MainTabbedPage">
</TabbedPage>
Page1 的 View 內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XFTabbed2.Views.Page1"
Title="{Binding Title}"
BackgroundColor="LightBlue">
<StackLayout
>
<Button
Text="Go Page21"
Command="{Binding GoNextCommand}"/>
</StackLayout>
</ContentPage>
Page1ViewModel 的 ViewModel 程式碼
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace XFTabbed2.ViewModels
{
using System.ComponentModel;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
public class Page1ViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public string Title { get; set; }
private readonly INavigationService _navigationService;
public DelegateCommand GoNextCommand { get; set; }
public Page1ViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
Title = "頁面 1";
GoNextCommand = new DelegateCommand(() =>
{
_navigationService.NavigateAsync("Page21");
});
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
}
}
}
Page2 的 View 內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XFTabbed2.Views.Page2"
Title="{Binding Title}"
BackgroundColor="LightGoldenrodYellow">
<StackLayout
>
<Button
Text="Go Page21"
Command="{Binding GoNextCommand}"/>
</StackLayout>
</ContentPage>
Page2ViewModel 的 ViewModel 程式碼
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace XFTabbed2.ViewModels
{
using System.ComponentModel;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
public class Page2ViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public string Title { get; set; }
private readonly INavigationService _navigationService;
public DelegateCommand GoNextCommand { get; set; }
public Page2ViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
Title = "頁面 2";
GoNextCommand = new DelegateCommand(() =>
{
_navigationService.NavigateAsync("Page21");
});
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
}
}
}
Page21 的 View 內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XFTabbed2.Views.Page21"
Title="{Binding Title}"
BackgroundColor="LightPink">
</ContentPage>
Page21ViewModel 的 ViewModel 程式碼
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace XFTabbed2.ViewModels
{
using System.ComponentModel;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
public class Page21ViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public string Title { get; set; }
private readonly INavigationService _navigationService;
public Page21ViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
Title = "頁面 21";
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
}
}
}
Page3 的 View 內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XFTabbed2.Views.Page3"
Title="{Binding Title}"
BackgroundColor="LightSalmon">
</ContentPage>
Page3ViewModel 的 ViewModel 程式碼
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace XFTabbed2.ViewModels
{
using System.ComponentModel;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
public class Page3ViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public string Title { get; set; }
private readonly INavigationService _navigationService;
public Page3ViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
Title = "頁面 3";
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
}
}
}
Page4 的 View 內容
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="XFTabbed2.Views.Page4"
Title="{Binding Title}"
BackgroundColor="LightSteelBlue">
</ContentPage>
Page4ViewModel 的 ViewModel 程式碼
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
namespace XFTabbed2.ViewModels
{
using System.ComponentModel;
using Prism.Events;
using Prism.Navigation;
using Prism.Services;
public class Page4ViewModel : INotifyPropertyChanged, INavigationAware
{
public event PropertyChangedEventHandler PropertyChanged;
public string Title { get; set; }
private readonly INavigationService _navigationService;
public Page4ViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
Title = "頁面 4";
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
}
}
}