Flutter中的路由和跳转,看这一篇就够了 (flutter 路由)
整理分享Flutter中的路由和跳转,看这一篇就够了 (flutter 路由),希望有所帮助,仅作参考,欢迎阅读内容。
内容相关其他词:flutter路由返回自动刷新,flutter路由统一统一管理,flutter路由统一统一管理,flutter 动态路由,flutter 路由,flutter auto_route,flutter lua,flutter fluro路由管理,内容如对您有帮助,希望把内容链接给更多的朋友!
使用Navigator.pop()返回到第一个路由上一小节已经实现了从第一个路由到第二个路由的跳转,那么跳转到第二个路由之后如果我们想要返回第一个路由应该怎么做?答案是使用Navigator.pop(),这里的pop()方*移除路由栈中栈顶的路由(也就是当前路由),自然也就返回到了前一个路由。具体到代码上是这样实现的://在SecondRoute的点击事件中onPressed:(){Navigator.pop(context);}运行效果是这样的:完整的代码及效果classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Assetsdemo',debugShowCheckedModeBanner:false,home:FirstRoute());}}classFirstRouteextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('FirstRoute'),),body:Center(child:RaisedButton(child:Text('Openroute'),onPressed:(){//Navigatetosecondroutewhentapped.Navigator.push(context,MaterialPageRoute(builder:(context)=>SecondRoute()),);},),),);}}classSecondRouteextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text("SecondRoute"),),body:Center(child:RaisedButton(onPressed:(){Navigator.pop(context);},child:Text('Goback!'),),),);}}完整的效果:使用命名路由进行导航在上一节我们介绍了如何导航到新的路由以及如何从路由中返回,这一节我们来介绍一下Flutter中的“命名路由”。为什么要有命名路由?试想一下,如果我们需要从app的多个位置导航到同一个路由,这种情况下如何使用上一节介绍的方法进行导航,就会造成代码的重复,所以指明命名路由来简化这一问题。我们可以通过使用Navigator.pushNamed()方法实现命名路由,接下来我会通过一个实例来介绍如何使用命名路由代替上一节介绍的路由跳转的方法。主要分为4步:创建两个页面定义路由使用Navigator.pushNamed()导航到第二个页面使用Navigator.pop()导航到第一个路由创建两个页面首先我们需要创建两个页面,第一个页面上有一个导航到第二个屏幕的按钮,第二个页面上有一个返回到第一个屏幕的按钮,具体的实现代码如下:classFirstScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('FirstScreen'),),body:Center(child:RaisedButton(child:Text('Launchscreen'),onPressed:(){//Navigatetosecondscreenwhentapped!},),),);}}classSecondScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text("SecondScreen"),),body:Center(child:RaisedButton(onPressed:(){//Navigatebacktofirstscreenwhentapped!},child:Text('Goback!'),),),);}}定义路由接下来我们需要通过为MaterialApp的构造函数提供initialRoute和routes参数来定义我们的路由。initialRoute定义了app启动时初始应该启动哪个路由,routes参数定义了可用的命名路由和应该在导航到这些路由时构建的Widget,实现代码如下:classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Assetsdemo',debugShowCheckedModeBanner:false,initialRoute:'/',routes:{//当导航到'/'的时候跳转到FirstScreen'/':(context)=>FirstScreen(),//当导航到"/second"的时候跳转到SecondScreen'/second':(context)=>SecondScreen(),});}}注意:当使用initialRoute参数的时候就不能设置home参数了。导航到第二个页面定义好路由之后我们就可以开始导航了,在这里例子中我们使用Navigator.pushNamed()函数来实现,实现代码如下://FirstScreenonPressed:(){//使用命名路由跳转到第二个页面Navigator.pushNamed(context,'/second');}效果图如下:返回到第一个页面返回第一个页面使用的是Navigator.pop()函数://SecondScreenonPressed:(){Navigator.pop(context);}效果图如下:完整的代码及效果完整代码如下:classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Assetsdemo',debugShowCheckedModeBanner:false,initialRoute:'/',routes:{//当导航到'/'的时候跳转到FirstScreen'/':(context)=>FirstScreen(),//当导航到"/second"的时候跳转到SecondScreen'/second':(context)=>SecondScreen(),});}}classFirstScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('FirstScreen'),),body:Center(child:RaisedButton(child:Text('Launchscreen'),onPressed:(){Navigator.pushNamed(context,'/second');},),),);}}classSecondScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text("SecondScreen"),),body:Center(child:RaisedButton(onPressed:(){Navigator.pop(context);},child:Text('Goback!'),),),);}}完整效果图如下:向新的页面发送数据通常,我们在导航到新的页面的同时还希望在向新页面发送一些数据,例如,当点击列表中的某一项后我们想要将被点击项的信息传递给展示详细信息的页面。在本例中,我们将创建一个Todos列表。当“待办事项”被点击时,我们将导航到一个新页面,该页面显示有关待办事项的详细信息,具体的实现分为4步:定义一个Todo类展示一个Todo类的列表创建一个详细信息页面,用来展示Todo对象的详情导航并传递数据到信息信息页定义Todo类首先,我们需要一个简单的*事项的抽象类,我们称之为Todo类,该类有两个成员变量:标题、描述:classTodo{finalStringtitle;finalStringdescription;Todo(this.title,this.description);}创建一个Todo类的列表接下来,我们要显示Todo实例的列表,在本例中,我们将生成个待办事项,并使用ListView显示它们。生成Todo类的列表数据finaltodos=List.generate(,(i)=>Todo('Todo$i','AdescriptionofwhatneedstobedoneforTodo$i',),);使用ListView展示Todo类的列表ListView.builder(itemCount:todos.length,itemBuilder:(context,index){returnListTile(title:Text(todos[index].title),);},);创建详细信息页面现在,我们将创建第二个页面,屏幕的标题将展示待办事项(Todo对象)的标题(title),屏幕的正文将显示描述(description),实现代码如下:classDetailScreenextendsStatelessWidget{//声明Todo对象的占位符finalTodotodo;//构造函数中需要传入Todo对象DetailScreen({Keykey,@requiredthis.todo}):super(key:key);@overrideWidgetbuild(BuildContextcontext){//基于Todo对象的内容构建UIreturnScaffold(appBar:AppBar(title:Text(todo.title),),body:Padding(padding:EdgeInsets.all(.0),child:Text(todo.description),),);}}导航并传递数据到信息信息页定义好详细信息页,我们就可以执行导航了,在我们的示例中,当用户点击我们列表中的某个Todo项时,我们希望导航到详细信息页,在导航的同时将被点击的Todo对象传递给详细信息页。为此,我们将为ListTileWidget编写一个onTap回调,在onTap回调中,我们使用Navigator.push()方法实现路由导航:ListView.builder(itemCount:todos.length,itemBuilder:(context,index){returnListTile(title:Text(todos[index].title),//当用户点击当前ListTile,即导航到DetailScreen,导航的同时将当前Todo对象传递过去onTap:(){Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailScreen(todo:todos[index]),),);},);完整的代码及效果classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Assetsdemo',debugShowCheckedModeBanner:false,home:FirstRoute());}}classFirstRouteextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('TodoList'),),body:ListView.builder(itemCount:todos.length,itemBuilder:(context,index){returnListTile(title:Text(todos[index].title),//当用户点击当前ListTile,即导航到DetailScreen,导航的同时将当前Todo对象传递过去onTap:(){Navigator.push(context,MaterialPageRoute(builder:(context)=>DetailScreen(todo:todos[index]),),);},);},),);}}classDetailScreenextendsStatelessWidget{//声明Todo对象的占位符finalTodotodo;//构造函数中需要传入Todo对象DetailScreen({Keykey,@requiredthis.todo}):super(key:key);@overrideWidgetbuild(BuildContextcontext){//基于Todo对象的内容构建UIreturnScaffold(appBar:AppBar(title:Text(todo.title),),body:Padding(padding:EdgeInsets.all(.0),child:Text(todo.description),),);}}效果图如下:从当前页面返回数据给前一个页面在某些情况下,我们可能希望从新页面返回数据给前一个页面。例如,假设我们导航到了一个新页面,新页面中有两个不同的按钮,当用户点击某个按钮后,我们希望通知第一个页面用户点击的是哪一个,以便前一个页面可以根据该信息执行不同的逻辑。实现的方法还是使用Navigator.pop(),这里还是以一个实例进行说明,实例的实现分为5步:定义初始页面为添加一个导航到选择页面的按钮展示具有两个按钮的选择页面当选择页面中的某一个按钮被点击后,关闭选择页面在初始页面显示选择页面点击的是哪个按钮定义初始页面初始页面主要是展示一个按钮,当用户点击了这个按钮后导航到第二个页面(选择页面):classHomeScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('ReturningDataDemo'),),//这里的SelectionButton将在下一小节实现body:Center(child:SelectionButton()),);}}添加导航到选择页面的按钮现在我们应该创建上一小节用到的SelectionButton类了,该方法的作用是创建并返回一个按钮,这个按钮需要实现2个功能:被点击后导航到选择页面接收选择页面的返回结果实现代码如下:classSelectionButtonextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnRaisedButton(onPressed:(){_navigateAndDisplaySelection(context);},child:Text('Pickanoption,anyoption!'),);}//导航到选择页面并等待选择页面的返回结果_navigateAndDisplaySelection(BuildContextcontext)async{//Navigator.push()返回的Future类型的变量将在Selection中调用Navigator.pop()后完成finalresult=awaitNavigator.push(context,//We'llcreatetheSelectionScreeninthenextstep!MaterialPageRoute(builder:(context)=>SelectionScreen()),);}}展示具有2个按钮的选择页面现在,我们需要建立一个选择页面,它将包含两个按钮,当用户点击按钮时,它应该关闭选择页面,并让初始页面知道哪个按钮被点击了。我们先来定义UI,在下一步将实现数据的返回:classSelectionScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('Pickanoption'),),body:Center(child:Column(mainAxisAlignment:MainAxisAlignment.center,children:[Padding(padding:constEdgeInsets.all(8.0),child:RaisedButton(onPressed:(){},child:Text('黑'),),),Padding(padding:constEdgeInsets.all(8.0),child:RaisedButton(onPressed:(){},child:Text('白'),),)],),),);}}当按钮被点击后关闭选择页面现在,我们要更新两个按钮的Onpress回调,为了将数据返回到第一个页面,我们需要使用Navigator.pop()方法。了这个Navigator.pop()方法可以接收一个可选的称为result的参数,如果我们在调用它的时候提供了这个result参数,它将会把result以Future的形式返回,具体的我们来看实现:“黑”RaisedButton(onPressed:(){Navigator.pop(context,'黑');},child:Text('黑'),);“白”RaisedButton(onPressed:(){Navigator.pop(context,'白');},child:Text('白'),);在初始页面将选择页面的返回值显示出来//导航到选择页面并等待选择页面的返回结果_navigateAndDisplaySelection(BuildContextcontext)async{//Navigator.push()返回的Future类型的变量将在Selection中调用Navigator.pop()后完成finalresult=awaitNavigator.push(context,MaterialPageRoute(builder:(context)=>SelectionScreen()),);//当选择页面的结果返回后,隐藏之前的snackbar,将结果显示在新的snackbar上Scaffold.of(context)..removeCurrentSnackBar()..showSnackBar(SnackBar(content:Text("$result")));}完整的代码及效果classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Assetsdemo',debugShowCheckedModeBanner:false,home:HomeScreen());}}classHomeScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('ReturningDataDemo'),),//We'llcreatetheSelectionButtonWidgetinthenextstepbody:Center(child:SelectionButton()),);}}classSelectionButtonextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnRaisedButton(onPressed:(){_navigateAndDisplaySelection(context);},child:Text('Pickanoption,anyoption!'),);}//导航到选择页面并等待选择页面的返回结果_navigateAndDisplaySelection(BuildContextcontext)async{//Navigator.push()返回的Future类型的变量将在Selection中调用Navigator.pop()后完成finalresult=awaitNavigator.push(context,MaterialPageRoute(builder:(context)=>SelectionScreen()),);//当选择页面的结果返回后,隐藏之前的snackbar,将结果显示在新的snackbar上Scaffold.of(context)..removeCurrentSnackBar()..showSnackBar(SnackBar(content:Text("$result")));}}classSelectionScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('Pickanoption'),),body:Center(child:Column(mainAxisAlignment:MainAxisAlignment.center,children:[Padding(padding:constEdgeInsets.all(8.0),child:RaisedButton(onPressed:(){Navigator.pop(context,'黑');},child:Text('黑'),),),Padding(padding:constEdgeInsets.all(8.0),child:RaisedButton(onPressed:(){Navigator.pop(context,'白');},child:Text('白'),),)],),),);}}完成后的运行效果如下:导航时的动画处理作为一款优质的app,我们不能仅限于实现页面之间的导航,更重要的要考虑如何使用一个优美的动画实现两个页面之间的优雅过渡(切换),本节将介绍如何为页面之间的导航添加动画,主要使用的是Flutter为我们提供的HeroWidget。本节还是继续以实例的形式进行知识点的介绍,我们要实现的效果是,在两个页面上显示相同的图像,当用户点击图像时,对图像进行从第一个页面到第二个页面的动画处理。我们将通过以下3步实现一个示例:创建两个显示同一张图片的页面为第一个页面添加HeroWidget为第二个页面添加HeroWidget创建两个显示同一张图片的页面我们首先来创建显示图片的页面:classMainScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('MainScreen'),),body:GestureDetector(onTap:(){Navigator.push(context,MaterialPageRoute(builder:(_){returnDetailScreen();}));},child:Image.asset('images/pic.jpeg')),);}}classDetailScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:GestureDetector(onTap:(){Navigator.pop(context);},child:Center(child:Image.asset('images/pic.jpeg')),),);}}为第一个页面添加HeroWidget为了使用动画对两个屏幕进行过渡,我们需要将ImageWidget包裹在HeroWidget中,HeroWidget在使用的时候需要两个参数:tag:Hero的标识参数,两个页面的HeroWidget的这个参数必须一样child:需要被动画过渡的Widget具体的实现代码如下:classMainScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('MainScreen'),),body:GestureDetector(onTap:(){Navigator.push(context,MaterialPageRoute(builder:(_){returnDetailScreen();}));},child:Hero(tag:'bestGirl',child:Image.asset('images/pic.jpeg'))),);}}为第二个页面添加HeroWidget为了实现两个页面的过渡,我们也需要使用HeroWidget包裹第二个页面的ImageWidget,注意第二个页面Hero中的tag参数必须和第一个页面中的一样:classDetailScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:GestureDetector(onTap:(){Navigator.pop(context);},child:Hero(tag:'bestGirl',child:Image.asset('images/pic.jpeg'))),);}}完整的代码及效果classMyAppextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Assetsdemo',debugShowCheckedModeBanner:false,home:MainScreen());}}classMainScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text('MainScreen'),),body:GestureDetector(onTap:(){Navigator.push(context,MaterialPageRoute(builder:(_){returnDetailScreen();}));},child:Hero(tag:'bestGirl',child:Image.asset('images/pic.jpeg'))),);}}classDetailScreenextendsStatelessWidget{@overrideWidgetbuild(BuildContextcontext){returnScaffold(body:GestureDetector(onTap:(){Navigator.pop(context);},child:Hero(tag:'bestGirl',child:Image.asset('images/pic.jpeg'))),);}}完整效果如下:嘿嘿,原谅我不厚道地给图中的小仙女打了码,我的女朋友怎么可以随便给你们看哈哈~好了,至此我们已经介绍完了Flutter中路由和导航的常见用法,希望大家可以通过通过本文对路由和导航有更深刻的认识,下一期文章我们将会介绍Flutter中的动画,欢迎大家持续关注~