在最初接触Xamarin.Forms的时候,我是跟着Xamarin官方的名为“learning-xamarin-ebook”的pdf文档进行学习的,我在成功运行Hello world程序以后,我开始跟着pdf写上面的monkey实例,然而我却遇到了一个问题,我在列表页点击某一个Item的时候,不能如示例上面所展现的那样跳转到详细页面。也正由于此我在官方文档和电子书中寻找答案,也将本身的学习的东西作个简单的笔记和分享。安全
在Froms的中的提供了以下方法用于导航:app
Task PushAsync(Page page)和Task PushModalAsync(Page page)导航到其余页面;less
Task<Page> PopAsync()和Task<Page> PopModalAsync()返回到前一页;ide
这四个方法都被定义在一个INavigation接口中,而VisualElement中又定义了一个名为Navigation的只读的INavigation的属性,其余Page又直接或间接继承了这个类。因此咱们能够在代码中直接作以下调用:函数
await Navigation.PushAsync(Page page)学习
await Navigation.PopAsync()动画
然而你要想成功调用这四个导航方法,你必须在App类的构造函数中作一些改变,即便用NavigationPage对你得主页(MainPage)作一个简单的封装,而这也就是我先前跳转页面不成功的缘由,以下:ui
为何要这样呢?由于毕竟跨平台,只有这样才能在各个平台上实现Page的生命周期,其实就是为了兼容Android(毕竟英文,有些记得不是太清楚,有问题你们指正)。这四个方法都提供了另外一个重载,都多了一个参数:bool animated(默认为true),根据参数名,你应该也知道这个参数的做用了,但实际上,默认的跳转页面的动画还算能够,通用的那种,固然貌似也能够重写,在电子书的动画那章应该有讲,不过目前我还没看。。。。。。this
好了,在继续正题以前,还有两个要点,一是在Froms中的Page在各个平台中是不同的,一个Froms的Page至关于IOS的view Control,也至关于WP的Page,可是并非Android的Activity,这里给你们给你们贴一下电子书中的原文,官网中的本身搜一下就行spa
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 activ-ity, or a fragment of an activity.
也正是由于各个平台的不一样,Page中的可重写的方法的调用顺序也多不一样。这个后面说。第二个就是modal page和modeless page,正常的讲在各个平台都没有对他们明确的区分和定义,在视觉上最直观的区别就是默认状况下(导航栏也是能够经过设置进行显示和隐藏)在左上角是否有返回按钮(WP没有,WP和Android都有返回的物理按键,只不过Android在页面也有返回键),而在代码中则体现为跳转页面时调用的是PushAsync仍是PushModalAsync方法。以下图(截得的电子书中的图):
如上图左边是modeless page而右边则是modal page,正如你所看到的,若是你跳转的页面是modeless page在各个平台,你是不须要在页面中再提供返回按键的,而modal page则有不一样,因为WP和Android都有物理的返回按键支持,因此若是你在modal page中不提供返回按钮,也并无关系,然而在IOS中,你必须提供,为何,固然是由于它没有提供返回的物理按键,只有Home键。固然WP和Android的物理返回按键也是也已禁用的,若是你存在非要用户完成某些操做的“流氓”行为,就是重写OnBackButtonPressed方法便可,以下:
protected override bool OnBackButtonPressed() { if(flag) { return base.OnBackButtonPressed(); } return true; }
而且modal page只能跳转到另外一个modal page,而modeless page能跳转到modal page和modeless page。
如今说一下NavigationPage的经常使用属性和方法:
一、BarBackgroundColor和BarTextColor都是Color类型的属性,看名字就知道其用途,这两个属性在IOS和Win10都会生效,在Android上去只有背景色(BarBackgroundColor)会生效.
代码以下:
public static Page GetMainPage() { var monkeyPage = new MonkeysPage(); return new NavigationPage(monkeyPage) { BarBackgroundColor=Color.Green,BarTextColor=Color.Blue }; }
如图(我只有安卓机,因此本身的图只有安卓的,对比图我就直接截电子书的,之后都是):
官方免费电子书对比图以下:
二、SetBackButtonTitle方法,这个只有IOS才会生效,应为只有IOS会显示前一页的Title。
三、SetTitleIcon方法,这个在IOS中将替换Title属性,Android替换图标。
以上两个并不会做用于Windows和WP。
四、SetHasNavigationBar和SetHasBackButton这两个就是分别设置是否显示导航栏和是否显示导航栏的的返回图标。
方法并不能在App中设置,只能在Page的构造函数中设置,调用方式以下:
namespace App3.Views { public partial class DetailsPage : ContentPage { public DetailsPage(Monkey monkey) { InitializeComponent();
//其余方法大同小异 NavigationPage.SetHasNavigationBar(this, false); this.BindingContext = monkey; } } }
我们继续,当咱们调用Push或者Pop方法是返回的老是Task对象,是否是意味着若是咱们使用await来调用方法,会出现等待呢?官方的描述为:task completes rather quickly。并且官方建议在调用Push或者Pop方法的时候,必定要用await,为何?由于在某些状况下page stack是不安全的,我须要使用await来确保已经获取到了下一个页面的实例,而且已安全的写入到了page stack中。若是你在看这篇文章的时候你也F12到了INavigation接口中,你会看到接口内定义了两个IReadOnlyList<Page>的对象。
IReadOnlyList<T>看名字你就知道他是一个只读的,可是他跟Stack<T>类似,都是先进后出,或者你就把它看成是Stack<T>理解也行,只不过前者是只读的而已。在IOS中ModalStack始终为空的。
咱们NavigationPage对象中的CurrentPage的值为NavigationStack的最后一个进栈的,简单点就是CurrentPage若是有值,那只能是modeless page。
在Page对象中咱们还看到了两个能够重写的方法:
protected virtual void OnDisappearing();
protected virtual void OnAppearing();
这两个方法又是何时执行,执行顺序又是什么?咱们这里用PushAsync和PushModalAsync:
一、页面调用PushAsync或者PushModalAsync一般将会获取当前页面的OnDisappearing方法重写的调用
二、而后获取下一个页面的OnAppearing方法的重写的调用
三、PushAsync或者PushModalAsync完成
而当咱们调用PopAsync或者PopModalAsync的执行顺序以下:
一、页面调用PopAsync或者PopModalAsync将会获取当前页面的OnDisappearing方法重写的调用
二、而后一般获取上一个页面的OnAppearing方法的重写的调用
三、PopAsync或者PopModalAsync完成
是的,我把”一般“用红色的标注了,为何,先前也说过Froms Page并非一个Android的Actively,因此有些不一样,调用PushModalAsync的时候不会调用OnDisappearing,而调用PopModalAsync的时候是不会调用前一页的OnAppearing,至于为何,当我把下一个页面设置为透明(在构造函数中设置BackgroupColor=Color.FromRgba(0,0,0,0.5)),而后用modal page的方式导航过去的时候就知道了,以下图:
是的,如你所见,前一页并无销毁,而是存在的,so。。。不须要我再解释了吧!若是你非要问为何没有销毁,个人答案是:呵呵!
而在IOS中,OnDisappearing的调用是在一个页面彻底销毁的时候,而不是在调用Push或者Pop的时候。
好了,就这么,艰苦的一年啊!