Flutter(二十三)——静态路由与动态路由

夙愿已清 提交于 2020-03-07 20:31:39

前言

前面讲解过一些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),
      ),
    );
  }

}

这里也就一个常规的代码片段,定义了一个标题,居中显示新闻的详情内容,然后我们就实现了如博文开头所示的操作。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!