Loading

Flutter 应用入门:路由管理

路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController。所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。Flutter中的路由管理和原生开发类似,无论是Android还是iOS,导航管理都会维护一个路由栈,路由入栈(push)操作对应打开一个新页面,路由出栈(pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。

// 路由管理


// 导入包
import 'package:flutter/material.dart';

// 应用入口,启动Flutter应用,runApp它接受一个Widget参数
void main() => runApp(MyApp());


// MyApp类代表Flutter应用,它继承了 StatelessWidget类,这也就意味着应用本身也是一个widget
class MyApp extends StatelessWidget {
  // widget的主要工作是提供一个build()方法来描述如何构建UI界面(通常是通过组合、拼装其它基础widget)
  @override
  Widget build(BuildContext context) {
    // MaterialApp是Material库中提供的Flutter APP框架,通过它可以设置应用的名称、主题、语言、首页以及路由列表等,它本身也是一个widget
    return MaterialApp(
      // 应用名称
      title: 'Flutter Demo',
      // 名为"home"的路由作为应用的home(首页)
      initialRoute: 'hmoe',

      // 应用主题
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),

      // 注册路由表
      routes: {
        'new page':(context) => NewRoute(),
        // 将首页路由也注册为命名路由
        'home':(context) => MyHomePage(title: 'Flutter Demo Home Page'),
      },

      // 应用首页路由,本身也是一个widget
      home: MyHomePage(title: 'Flutter Demo Home Page'),

    );
  }
}


// Flutter应用的首页
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}
// 有状态的组件(Stateful widget) 和无状态的组件(Stateless widget)有两点不同:
// 1. Stateful widget可以拥有状态,这些状态在widget生命周期中是可以变的,而Stateless widget是不可变的。
// 2. Stateful widget至少由两个类组成:
// 一个StatefulWidget类;
// 一个State类,StatefulWidget类本身是不变的,但是State类中持有的状态在widget生命周期中可能会发生变化。


// 新路由,显示一句话
class NewRoute extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('New route'),
      ),
      body: Center(
        child: Text('This is new route'),
      ),
    );
  }

}


// 路由传值。它接受一个提示文本参数,负责将传入它的文本显示在页面上,
// 另外TipRoute中我们添加一个“返回”按钮,点击后在返回上一个路由的同时会带上一个返回参数。
class TipRoute extends StatelessWidget {
  final String text;
  TipRoute({
    Key key,
    @required this.text,  // 接收一个text参数
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('提示'),
      ),
      body: Padding(
        padding: EdgeInsets.all(18),
        child: Column(
          children: <Widget>[
            Text(text),
            RaisedButton(
              onPressed: () => Navigator.pop(context, '我是返回值'),
              child: Text('返回'),
            )
          ],
        ),
      ),
    );
  }
}


//// 打开TipRoute,已合并到_MyHomePageState了
//class RouterTestRoute extends StatelessWidget {
//  @override
//  Widget build(BuildContext context) {
//    return Center(
//      child: RaisedButton(
//        onPressed: () async {
//          // 打开TipRoute,并等待返回结果
//          var result = await Navigator.push(context, MaterialPageRoute(
//            builder: (context) {
//              return TipRoute(
//                // 路由参数
//                text: '我是提示***',
//              );
//            }
//          ));
//          // 输出TipRoute路由返回结果
//          print('路由返回值:$result');
//        },
//        child: Text('打开提示页'),
//      ),
//    );
//  }
//}


class _MyHomePageState extends State<MyHomePage> {
  // 组件的状态,记录按钮点击的总次数
  int _counter = 0;

  // 设置状态的自增函数
  /* 当按钮点击时,会调用此函数,该函数的作用是先自增_counter,然后调用setState 方法。
  setState方法的作用是通知Flutter框架,有状态发生了改变,Flutter框架收到通知后,会执行build方法来根据新的状态重新构建界面,
  Flutter 对此方法做了优化,使重新执行变的很快,所以你可以重新构建任何需要更新的东西,而无需分别去修改各个widget。
  */
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  //
  @override
  Widget build(BuildContext context) {
    // Scaffold是Material库中提供的页面脚手架,它提供了默认的导航栏、标题和包含主屏幕widget树的body属性。
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      // Center组件,可以将其子组件树对齐到屏幕中心
      body: Center(
        // Column组件,可以将其所有子组件沿屏幕垂直方向依次排列
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            // 添加一个新按钮
            FlatButton(
              child: Text('Open new route!'),
              textColor: Colors.blue,
              onPressed: () {
//                // 导航到新路由
//                Navigator.push(context,
//                    MaterialPageRoute(builder: (context) {
//                      return NewRoute();
//                    }));

                // 通过路由名称来打开新路由
                Navigator.pushNamed(context, 'new page');
              },
            ),
            // 添加一个新按钮
            RaisedButton(
              onPressed: () async {
                // 打开TipRoute,并等待返回结果
                var result = await Navigator.push(context, MaterialPageRoute(
                    builder: (context) {
                      return TipRoute(
                        // 路由参数
                        text: '我是提示信息哦!',
                      );
                    }
                ));
                // 输出TipRoute路由返回结果
                print('路由返回值:$result');
              },
              child: Text('打开提示页'),
            ),
          ],
        ),
      ),
      // 页面右下角的带“+”的悬浮按钮,它的onPressed属性接受一个回调函数,代表它被点击后的处理器
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}


总结

介绍了Flutter中路由管理、传参的方式,然后又着重介绍了命名路由相关内容。在此需要说明一点,由于命名路由只是一种可选的路由管理方式,在实际开发中,可能心中会犹豫到底使用哪种路由管理方式。在此,根据经验,建议最好统一使用命名路由的管理方式,这将会带来如下好处:

  1. 语义化更明确。
  2. 代码更好维护;如果使用匿名路由,则必须在调用Navigator.push的地方创建新路由页,这样不仅需要import新路由页的dart文件,而且这样的代码将会非常分散。
  3. 可以通过onGenerateRoute做一些全局的路由跳转前置处理逻辑。
posted @ 2019-12-17 14:43  Parzulpan  阅读(405)  评论(0编辑  收藏  举报