一個(gè)常規(guī)的App是由多個(gè)Page組成的得哆,出現(xiàn)多個(gè)Page就會(huì)涉及頁(yè)面跳轉(zhuǎn)問(wèn)題迹辐。Xamarin.Forms頁(yè)面之間的跳轉(zhuǎn)通過(guò)Navigation Stack管理Page呵萨,如頁(yè)面A跳轉(zhuǎn)到頁(yè)面B時(shí)撒犀,會(huì)將B壓入棧定某宪,此時(shí)頁(yè)面B成為活動(dòng)頁(yè)面仿村,執(zhí)行Back操作時(shí),頁(yè)面B從棧定推出使頁(yè)面A重新變?yōu)榛顒?dòng)頁(yè)面缩抡。
每個(gè)應(yīng)用程序都有一個(gè)特殊頁(yè)作為應(yīng)用程序的入口(main page, or the home page, or the start page)奠宜,Xamarin.Forms中由App的MainPage屬性設(shè)置。
INavigation介紹
Xamarin.Forms中頁(yè)面分為Modal pages(模態(tài)頁(yè)面) 和 modeless pages(非模態(tài)頁(yè)面)瞻想,跳轉(zhuǎn)到一個(gè)新的頁(yè)面可以通過(guò)PushAsync
和PushModalAsync
兩個(gè)方法實(shí)現(xiàn)压真,兩個(gè)方法均傳入一個(gè)Page對(duì)象作為參數(shù)。同樣提供了PopAsync
和PopModalAsync
兩個(gè)方法返回前一個(gè)頁(yè)面蘑险。PushAsync和PopAsync是對(duì)非模態(tài)頁(yè)面的操作滴肿,PushModalAsync和PopModalAsync操作的是模態(tài)頁(yè)面。PopToRootAsync方法表示回到導(dǎo)航棧低頁(yè)面佃迄。RemovePage方法從導(dǎo)航棧中刪除一個(gè)頁(yè)面泼差。InserPageBefore方法將一個(gè)page插入到指定page之前。通過(guò)這些方法操作Navigation Stack可以在不同Page間跳轉(zhuǎn)呵俏。
關(guān)于PopXXX和Push方法定義返回Task類(lèi)型介紹參考(涉及的OnDisappearing和OnAppearing不在本文不再說(shuō)明):
http://www.cnblogs.com/qiandi/p/5598742.html
當(dāng)我們調(diào)用PushAsync方法時(shí)必須修改App的MainPage屬性為NavigationPage對(duì)象堆缘,否則報(bào)如下異常,使用NavigationPage時(shí)不必在為iOS單獨(dú)設(shè)置Page的Padding屬性解決頁(yè)面和狀態(tài)欄遮蓋問(wèn)題普碎。
PopXXX和PushXXX提供的bool類(lèi)型參數(shù)重載方法設(shè)置為true增加頁(yè)面跳轉(zhuǎn)動(dòng)畫(huà)吼肥。
INavigation還定義了兩個(gè)IReadOnlyList<Page>類(lèi)型屬性ModalStack
和NavigationStack
,NavigationStack表示非模態(tài)頁(yè)面的集合,PushAsync和PopAsync會(huì)改變NavigationStack的內(nèi)容缀皱,ModalStack表示模態(tài)頁(yè)面的集合PushModalAsync和PopModalAsync會(huì)改變ModalStack的內(nèi)容斗这,這兩個(gè)屬性不能直接修改,且提供了類(lèi)似堆棧的功能啤斗。這兩個(gè)集合不能混合跳轉(zhuǎn)表箭,非模態(tài)頁(yè)面可以導(dǎo)航到模態(tài)頁(yè)面但是模態(tài)頁(yè)面不能導(dǎo)航到非模態(tài)頁(yè)面。
如果用MainPage = new NavigationPage(new Page0());
初始化App的MainPage屬性運(yùn)行應(yīng)用程序钮莲,此時(shí)IOS平臺(tái)中ModalStack為空免钻,Android和Windows平臺(tái)ModalStack包含一個(gè)元素(MainPage對(duì)應(yīng)NavigationPage實(shí)例)。三個(gè)平臺(tái)中的NavigationStack集合包均含一個(gè)Page0的實(shí)例崔拥。
這些方法均定義在INavigation中伯襟,VisualElement提供了一個(gè)INavigation類(lèi)型只讀屬性Navigation,可以通過(guò)調(diào)用Navigation的方法實(shí)現(xiàn)跳轉(zhuǎn)握童。
頁(yè)面中調(diào)用代碼Navigation.PushAsync(new ModelessPage(), true);
Programmers familiar with Android architecture are sometimes curious how Xamarin.Forms page navigation integrates with the aspect of Android application architecture known as the activity. A Xamarin.Forms application running on an Android device comprises only one activity, and the page navigation is built on top of that. A ContentPage is a Xamarin.Forms object; it is not an Android activity, or a fragment of an activity.
前面提到的參考鏈接有說(shuō)明姆怪,什么意思自己看看吧!T杓ā稽揭!
NavigationPage介紹
NavigationPage的作用就是導(dǎo)航管理頁(yè)面。
NavigationPage提供的屬性
- BarBackgroundColor - 獲取肥卡、設(shè)置NavigationPage頂部導(dǎo)航欄的背景色(iOS溪掀、Android、Windows 平臺(tái)有效)步鉴。
- BarTextColor - 獲取揪胃、設(shè)置NavigationPage頂部導(dǎo)航欄顯示文本顏色(iOS、Windows平臺(tái)有效)氛琢。
不同平臺(tái)效果:
- CurrentPage - 獲取Navigation Stack最頂部頁(yè)面喊递,不管當(dāng)前顯示頁(yè)面是模態(tài)頁(yè)面還是非模態(tài)頁(yè)面,CurrentPage都表示NavigationStack集合中的最后一項(xiàng)阳似。
when a modal page is active, CurrentPage continues to indicate the last modeless page that was active before navigation to a modal page
NavigationPage提供的BindableProperty
-
HasBackButtonProperty - 是否顯示非模態(tài)頁(yè)面導(dǎo)航欄的返回按鈕(iOS骚勘、Android起作用)
C#設(shè)置NavigationPage.SetHasBackButton(this, false);
XAML設(shè)置NavigationPage.HasBackButton="False"
- HasNavigationBarProperty - 是否顯示導(dǎo)航欄
- BackButtonTitleProperty - 設(shè)置返回按鈕的文本(僅iOS平臺(tái))
- TitleIconProperty - 設(shè)置導(dǎo)航欄上顯示圖標(biāo)(iOS平臺(tái)Icon代替Title,Android修改左側(cè)圖標(biāo)顯示撮奏,Windows 無(wú)效)
屏蔽Android泽疆、Windows Mobile 返回按鍵
Android和Windows Phone會(huì)包含一個(gè)返回鍵,返回鍵提供類(lèi)似PopAsync或PopModalAsync的工能玲献,程序中要屏蔽返回鍵的功能需要重寫(xiě)Page的OnBackButtonPressed
方法殉疼。OnBackButtonPressed方法返回true值逗嫡,程序不處理返回按鍵。
protected override bool OnBackButtonPressed()
{
//return base.OnBackButtonPressed();
return true;
}
Page還定義了SendBackButtonPressed
方法株依,用來(lái)模擬返回按鈕被按下。調(diào)用該方法與Android按下返回鍵功能類(lèi)似延窜。
官方電子書(shū)中提到“Although this works on iOS and Android, it currently does not work on the Windows Runtime platforms.”這個(gè)方法只對(duì)iOS和Android有效恋腕,Windows Runtime platforms不能正常工作。 實(shí)際測(cè)試iOS無(wú)效逆瑞,Android正常荠藤,Windows 無(wú)法測(cè)試。
頁(yè)面間傳值
一個(gè)應(yīng)用程序會(huì)包含多個(gè)頁(yè)面获高,把數(shù)據(jù)從一個(gè)頁(yè)面?zhèn)鞯搅硪粋€(gè)頁(yè)面該怎么做哈肖?
構(gòu)造函數(shù)傳值
頁(yè)面跳轉(zhuǎn)的PushXXX方法傳入Page頁(yè)面實(shí)例作為參數(shù),可以通過(guò)Page頁(yè)面的構(gòu)造函數(shù)傳入數(shù)據(jù)念秧,如Navigation.PushModalAsync(new DataPage(label.Text));
淤井,在DataPage重載的構(gòu)造函數(shù)中在處理接收的數(shù)據(jù)。
屬性方法傳值
根據(jù)頁(yè)面的屬性或調(diào)用方法傳值摊趾。如:
構(gòu)造函數(shù)傳值是單向的不能傳遞返回?cái)?shù)據(jù)币狠,通過(guò)屬性傳值可以從當(dāng)前頁(yè)面向前一個(gè)頁(yè)面?zhèn)髦怠?yīng)從NavigationStack集合中取得前一個(gè)頁(yè)面實(shí)例砾层。
var stack = (App.Current.MainPage as NavigationPage).Navigation.NavigationStack;
int lastIndex = stack.Count - 1;
navigationPage homePage = stack[lastIndex] as navigationPage;
if (homePage == null)
{
homePage = stack[lastIndex - 1] as navigationPage;
}
homePage.SetText(Value + "頁(yè)面返回?cái)?shù)據(jù)了");
從模態(tài)頁(yè)面跳轉(zhuǎn)到非模態(tài)頁(yè)面和模態(tài)頁(yè)面跳轉(zhuǎn)到模態(tài)頁(yè)面兩種情況漩绵,跳轉(zhuǎn)前的頁(yè)面在NavigationStack中有不同的位置。如果是非模態(tài)頁(yè)面跳轉(zhuǎn)到非模態(tài)頁(yè)面肛炮?又要從ModalStack中獲取前一個(gè)頁(yè)面實(shí)例止吐,所以通過(guò)屬性和方法傳值不推薦!G仍恪碍扔!
Messaging Center傳值
MessagingCenter是一個(gè)靜態(tài)類(lèi),提供了Subscribe秕重、Unsubscribe和Send三個(gè)公開(kāi)的方法蕴忆。Subscribe訂閱接收的消息信息,參數(shù)悲幅、發(fā)送者類(lèi)型等套鹅。Unsubscribe取消訂閱,不在接收消息汰具。Send發(fā)送指定類(lèi)型消息卓鹿。
Messaging Center傳值示例:
數(shù)據(jù)接收頁(yè)面增加消息訂閱代碼:
MessagingCenter.Subscribe<navigationPage, string>(this, "Value", (arg1, arg2) =>
{
label.Text = arg2;
});
Subscribe包含兩個(gè)范型參數(shù),第一個(gè)為消息發(fā)送者類(lèi)型留荔,第二個(gè)為傳遞數(shù)據(jù)類(lèi)型吟孙。Subscribe包含三個(gè)參數(shù)澜倦,第一個(gè)為消息接收者,第二個(gè)參數(shù)為字符串類(lèi)型消息標(biāo)示杰妓,第三個(gè)參數(shù)是一個(gè)lambda表達(dá)式藻治,表示接收到消息后的動(dòng)作。
數(shù)據(jù)傳遞頁(yè)面增加發(fā)送消息代碼:
MessagingCenter.Send<navigationPage, string>(this, "Value", label.Text);
Send兩個(gè)范型參數(shù)與Subscribe方法相同巷挥。Send包含三個(gè)參數(shù)桩卵,第一個(gè)參數(shù)為消息發(fā)送者,第二個(gè)參數(shù)為消息標(biāo)示倍宾,第三個(gè)參數(shù)為傳遞的數(shù)據(jù)對(duì)象雏节。
本示例Send方法應(yīng)在PushAsync后執(zhí)行。PushAsync執(zhí)行前消息沒(méi)有訂閱高职,Send發(fā)送消息此時(shí)沒(méi)有接收者钩乍。
不再接收消息時(shí)應(yīng)該調(diào)用Unsubscribe取消指定消息的訂閱,對(duì)資源回收釋放。本示例取消訂閱代碼添加在Subscribe方法的lambda中怔锌。
MessagingCenter.Unsubscribe<navigationPage, string>(this, "Value");
Strictly speaking, however, unsubscribing shouldn’t be necessary because the MessagingCenter maintains WeakReference objects for subscribers寥粹。
MessagingCenter定義了一個(gè)Dictionary<Tuple<string, Type, Type>, List<Tuple<WeakReference, Action<object, object>>>>
類(lèi)型對(duì)象通過(guò)WeakReference管理subscribers,所以Unsubscribe方法不是必須的埃元。
事件傳值
WinForm中常用的傳值形式排作,事件傳值。推薦數(shù)據(jù)回傳時(shí)使用亚情。
Page1 跳轉(zhuǎn)到Page2時(shí)妄痪,Page2添加事件定義:
public EventHandler<string> Value;
Page2 返回Page1 時(shí),觸發(fā)事件:
EventHandler<string> handler = Value;
if (handler != null)
{
handler(this, "增加返回字符串");
}
Page1 跳轉(zhuǎn)到Page2時(shí)楞件,訂閱Page2的事件:
var page = new Page2();
page.Value += (sender, e) =>
{
label.Text = e;
};
Navigation.PushAsync(page);
傳遞復(fù)雜數(shù)據(jù)繼承
EventArgs
實(shí)現(xiàn)傳值
App Class傳值
Xamarin.Forms應(yīng)用程序會(huì)提供一個(gè)App類(lèi)(繼承Application)作為程序的入口衫生,該對(duì)象在應(yīng)用程序運(yùn)行期間一直存在,可以借助App類(lèi)實(shí)現(xiàn)不同頁(yè)面之間數(shù)據(jù)傳遞土浸。
修改App代碼定義屬性保存罪针、獲取數(shù)據(jù)。如:
獲取App類(lèi)實(shí)例可以通過(guò)(App)Application.Current)
獲取黄伊±峤矗或著直接定義static 屬性,直接通過(guò)App.Value 傳值还最。