前言
前面讲解过一些Flutter路由知识,比如讲解Hero动画的时候,就提到过路由的相关知识。其实路由是专业名词,就是界面切换,而跳转界面解释路由跳转。(下图为动态路由实现效果)
我们提到过,在Flutter开发中,路由的管理是通过堆栈的方式进行管理的,也就是说基本的用法就是push与pop方式,而在实际的项目中可没有那么简单,页面之间的跳转情况比较多,这就涉及到路由栈的管理知识,而路由的种类又分为静态路由与动态路由,下面我们分别来讲解这两种路由的方式。
静态路由
顾名思义,静态路由就是在知道明确跳往哪个界面时的情况下使用的。比如在MaterialApp构造函数里,我们可以定义路由列表。我们前面有介绍就是在main的入口函数里的runApp方法中传入,具体的代码使用如下:
import 'package:flutter/material.dart'; import 'package:route_flutter_app/page1.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: '静态路由', theme: ThemeData( primarySwatch: Colors.blue, ), routes: { '/page1':(context)=>Page1(title: "主页面",), '/page2':(context)=>Page2(title: "第二个页面",), '/page3':(context)=>Page3(title: "第三个页面",), '/page4':(context)=>Page4(title: "第四个页面",), }, onUnknownRoute: (RouteSettings setting){ String name=setting.name; print("没有匹配到路由"); return new MaterialPageRoute(builder: (context){ return new ErrorPage(title: "没有匹配的页面",); }); }, home: Page1(title: "主页面",), ); } }
上面这段代码中,我们通过home定义了主页面,routes定义了路由表,page1234就是我们的静态路由,也就是我们事先知道需要用到哪些界面,就是使用这种方式,而routes的参数是一个Map类型。
特别注意:MaterialApp还有一个属性,它就是initRoute,这个属性我们前面的章节也提到过,它指的是App启动的默认路由,也就是主页面,如果你使用了这个属性,那么就不需要指定home。
通过上面对应的路由表,我们可以直接使用Navigator.pushNamed方法进行跳转,但是,为了程序的严谨,我们还可以定义一个出错界面,也就是上面的onUnknownRoute,通过上面代码跳转到一个出错的自定义界面,以避免程序崩溃出错,增加用用户体验。
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class Page1 extends StatelessWidget{ final String title; Page1({Key key,@required this.title}):super(key:key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: Center( child: RaisedButton( child: Text("跳转到page2"), onPressed: (){ Navigator.pushNamed(context, "/page2"); }, ), ), ); } } class Page2 extends StatelessWidget{ final String title; Page2({Key key,@required this.title}):super(key:key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: Center( child: RaisedButton( child: Text("跳转到page3"), onPressed: (){ Navigator.pushNamed(context, "/page3"); }, ), ), ); } } class Page3 extends StatelessWidget{ final String title; Page3({Key key,@required this.title}):super(key:key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: Center( child: RaisedButton( child: Text("跳转到page4"), onPressed: (){ Navigator.pushNamed(context, "/page4"); }, ), ), ); } } class Page4 extends StatelessWidget{ final String title; Page4({Key key,@required this.title}):super(key:key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: Center( child: Text(this.title,style: new TextStyle(fontSize: 50,color: Colors.red),) ), ); } } class ErrorPage extends StatelessWidget{ final String title; ErrorPage({Key key,@required this.title}):super(key:key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: Center( child: Text(this.title,style: new TextStyle(fontSize: 50,color: Colors.red),) ), ); }
上面是我们定义的4个跳转界面,一个出错界面,代码都是基本的代码就不多做讲解了,这里我们的实现效果如下图所示:
在RaisedButton的onPress里,我们通过调用方法Navigator.pushNamed(context, “/page4”),这样就可以跳转到定义的路由表界面,当然也可以使用前面的push方法:
Navigator.of(context).push( new MaterialPageRoute( builder:(context){ return new Page4()}));
动态路由
虽然静态路由可以跳转界面,但是在大多数项目中,我们在两个界面之间跳转时需要携带参数,比如很多新闻类的App从列表跳转到新闻详情的界面。这个时候,动态路由就起作用了。下面我们先来看看代码,看动态路由是如何实现的,首先我们定义一个列表用到的新闻类News:
class News{ final String title; final String description; New(this.title,this.description); }
这里小编定义了一个新闻类,新闻类有两个变量,一个标题,一个详细情况,接着我们直接修改上面主页面page1的代码,如下所示:
class Page1 extends StatelessWidget{ final String title; Page1({Key key,@required this.title}):super(key:key); final news=List<News>.generate(20, (i)=>News("新闻 $i","新闻 $i的详细信息"),); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(this.title), ), body: ListView.builder(itemBuilder: (context,index){ return ListTile( title: Text(news[index].title), onTap: (){ Navigator.push( context, MaterialPageRoute( builder: (context)=>NewsDetail(s_new: news[index],), ) ); }, ); }, itemCount: news.length, ), ); } }
这里首先生成了一个20个元素的新闻列表,通过generate方法可以快速创建一个列表,接着通过ListView.builder方法生成listView列表,每个列表是一个ListTile,通过onTap方法监听点击事件,这里将点击的新闻类传递给NewsDetail详情界面:
Navigator.push( context, MaterialPageRoute( builder: (context)=>NewsDetail(s_new: news[index],), ) );
接着我们来看看我们详情界面的设置,代码如下:
class NewsDetail extends StatelessWidget{ final News s_new; NewsDetail({Key key,@required this.s_new}):super(key:key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(this.s_new.title),), body: Center( child: Text(this.s_new.description), ), ); }
这里也就一个常规的代码片段,定义了一个标题,居中显示新闻的详情内容,然后我们就实现了如博文开头所示的操作。