美文网首页
Flutter(十三):路由

Flutter(十三):路由

作者: 林ze宏 | 来源:发表于2020-07-22 09:40 被阅读0次

1 Flutter 中的路由

Flutter 中的路由通俗的讲就是页面跳转。在 Flutter 中通过 Navigator 组件管理路由导航。 并提供了管理堆栈的方法。如:Navigator.push 和 Navigator.pop

Flutter 中给我们提供了两种配置路由跳转的方式:1、基本路由 2、命名路由

2 基本路由

通过 Navigator 的 push 和 pop 方法实现路由的跳转和返回。通过构造函数传参,实现路由之间的参数传递。

import 'package:flutter/material.dart';
import './Detail.dart';

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          SizedBox(height: 100),
          RaisedButton(
            child: Text('go to Detail'),
            textColor: Theme.of(context).accentColor,
            textTheme: ButtonTextTheme.primary,
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => Detail(title: '我是从home进入的参数'),
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}



Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => Detail(title: '我是从home进入的参数'),
  ),
);
  • Detail.dart 详情页,新的组件外层需要返回 Scaffold 组件。
import 'package:flutter/material.dart';

class Detail extends StatefulWidget {
  final String title;
  Detail({Key key, this.title}) : super(key: key);

  @override
  _DetailState createState() => _DetailState(this.title);
}

class _DetailState extends State<Detail> {
  final String title;
  _DetailState(this.title);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton( // 实现浮动返回按钮
        child: Text('返回'),
        onPressed: () {
          // Navigator.pop(context);
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(
        title: Text(this.title ?? '详情'),
      ),
      body: Container(
        child: Column(
          children: <Widget>[
            Text('xxxxx'),
            SizedBox(height: 30),
          ],
        ),
      ),
    );
  }
}

效果

3 命名式路由

在 MaterialApp 中配置统一路由。

  • 命名式路由传参,方式一
main.dart 

import 'package:flutter/material.dart';

import 'tabs/Tabs.dart';
import 'package:app03/pages/home/Detail.dart';
import 'res/listData.dart';

void main() {
  runApp(new MyApp());
}

// 自定义组件
class MyApp extends StatelessWidget {
  // 1 配置统一命名路由
  final routes = {
    '/detail': (context) => Detail(
        routesArgs:
            ModalRoute.of(context).settings.arguments), // 2 根据组件构造函数参数,传递路由参数
  };

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      routes: routes,
      // Scaffold 定义导航头部和页面主要内容
      home: TabsPage(),
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
    );
  }
}

HomePage.dart

import 'package:flutter/material.dart';
import './Detail.dart';

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          SizedBox(height: 100),
          RaisedButton(
            child: Text('go to Detail'),
            textColor: Theme.of(context).accentColor,
            textTheme: ButtonTextTheme.primary,
            onPressed: () {
              Navigator.of(context).pushNamed(
                "/detail",
                arguments: {"id": 123}, // 3 使用 arguments 传值,注意类型
              );
              // Navigator.push(
              //   context,
              //   MaterialPageRoute(
              //     builder: (context) => Detail(title: '我是从home进入的参数'),
              //   ),
              // );
            },
          ),
        ],
      ),
    );
  }
}

Detail.dart

import 'package:flutter/material.dart';

class Detail extends StatefulWidget {
  final String title;
  // 4 定义对应的构造参数,注意类型要对应
  final Map routesArgs;
  Detail({Key key, this.title, this.routesArgs}) : super(key: key);

  @override
  _DetailState createState() => _DetailState();
}

class _DetailState extends State<Detail> {
  @override
  Widget build(BuildContext context) {
    // 5 组件内,获取路由参数
    var args = ModalRoute.of(context).settings.arguments;
    var _args = args as Map; // 如果参数不是为 String 类型,例如 Map 类型等其他类型,需要做强制转换
    print(_args['id']);

    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Text('返回'),
        onPressed: () {
          // Navigator.pop(context);
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(
        title: Text("详情${_args['id']}"),
        // title: Text("详情${(args as Map)['id']}"),
      ),
      body: Container(
        child: Column(
          children: <Widget>[
            Text('xxxxx'),
            SizedBox(height: 30),
          ],
        ),
      ),
    );
  }
}

  • 命名式路由传参,方式二
main.dart 

import 'package:flutter/material.dart';

import 'tabs/Tabs.dart';
import 'package:app03/pages/home/Detail.dart';
import 'package:app03/pages/home/FormPage.dart';
import 'res/listData.dart';

void main() {
  runApp(new MyApp());
}

// 自定义组件
class MyApp extends StatelessWidget {
  // 1 配置统一命名路由
  final routes = {
    '/detail': (context) => Detail(), // 2 根据组件构造函数参数,传递路由参数
    '/form': (context, {arguments}) => FormPage(arguments: arguments),
  };

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      // routes: routes, // 注意:方式二不用配置,方式一才需要,不然会有问题!!!
      // Scaffold 定义导航头部和页面主要内容
      home: TabsPage(),
      onGenerateRoute: (RouteSettings settings) {
        print('-------${settings.arguments}');
        // 统一处理
        final String name = settings.name;
        final Function pageContentBuilder = this.routes[name];
        if (pageContentBuilder != null) {
          if (settings.arguments != null) {
            final Route route = MaterialPageRoute(
                builder: (context) =>
                    pageContentBuilder(context, arguments: settings.arguments));
            return route;
          } else {
            final Route route = MaterialPageRoute(
                builder: (context) => pageContentBuilder(context));
            return route;
          }
        }
      },
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
    );
  }
}

HomePage.dart

import 'package:flutter/material.dart';
import './Detail.dart';

class HomePage extends StatefulWidget {
  HomePage({Key key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          SizedBox(height: 100),
          RaisedButton(
            child: Text('go to Detail'),
            textColor: Theme.of(context).accentColor,
            textTheme: ButtonTextTheme.primary,
            onPressed: () {
              Navigator.of(context)
                  .pushNamed("/detail"); // 如果不需要参数就不要写,不然有问题!!!
              // Navigator.push(
              //   context,
              //   MaterialPageRoute(
              //     builder: (context) => Detail(title: '我是从home进入的参数'),
              //   ),
              // );
            },
          ),
          SizedBox(height: 40),
          RaisedButton(
            child: Text('go to Form'),
            textColor: Theme.of(context).accentColor,
            textTheme: ButtonTextTheme.primary,
            onPressed: () {
              Navigator.pushNamed(context, '/form', arguments: {"id": 20});
              // Navigator.of(context).pushNamed(
              //   "/form",
              //   arguments: {"id": 4445}, // 3 使用 arguments 传值,注意类型
              // );
              // Navigator.push(
              //   context,
              //   MaterialPageRoute(
              //     builder: (context) => Detail(title: '我是从home进入的参数'),
              //   ),
              // );
            },
          ),
        ],
      ),
    );
  }
}

FormPage.dart

import 'package:flutter/material.dart';

class FormPage extends StatefulWidget {
  final Map arguments;
  // FormPage({this.arguments});
  FormPage({Key key, this.arguments}) : super(key: key);
  // print(arguments);
  @override
  _FormPageState createState() => _FormPageState(arguments: this.arguments);
}

class _FormPageState extends State<FormPage> {
  final Map arguments;
  _FormPageState({this.arguments});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Text('返回'),
        onPressed: () {
          // Navigator.pop(context);
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(
        title: Text("Form 表单"),
        // title: Text("详情${(args as Map)['id']}"),
      ),
      body: Container(
        child: Column(
          children: <Widget>[
            Text("我是一个表单页面 ${arguments != null ? arguments['id'] : '0'}"),
            SizedBox(height: 30),
          ],
        ),
      ),
    );
  }
}

// import 'package:flutter/material.dart';

// class FormPage extends StatelessWidget {
//   final Map arguments;
//   FormPage({this.arguments});
//   @override
//   Widget build(BuildContext context) {
//     // print(arguments);

//     return Scaffold(
//         appBar: AppBar(
//           title: Text("搜索"),
//         ),
//         body: Text("我是一个表单页面 ${arguments != null ? arguments['id'] : '0'}"));
//   }
// }

Detail.dart

import 'package:flutter/material.dart';

class Detail extends StatefulWidget {
  final String title;
  // 4 定义对应的构造参数,注意类型要对应
  final Map routesArgs;
  Detail({Key key, this.title, this.routesArgs}) : super(key: key);

  @override
  _DetailState createState() => _DetailState();
}

class _DetailState extends State<Detail> {
  @override
  Widget build(BuildContext context) {
    // 5 组件内,获取路由参数
    // var args = ModalRoute.of(context).settings.arguments;
    // var _args = args as Map; // 如果参数不是为 String 类型,例如 Map 类型等其他类型,需要做强制转换
    // print(_args['id']);

    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Text('返回'),
        onPressed: () {
          // Navigator.pop(context);
          Navigator.of(context).pop();
        },
      ),
      appBar: AppBar(
        title: Text("详情"),
        // title: Text("详情${_args['id']}"),
        // title: Text("详情${(args as Map)['id']}"),
      ),
      body: Container(
        child: Column(
          children: <Widget>[
            Text('xxxxx'),
            SizedBox(height: 30),
          ],
        ),
      ),
    );
  }
}

4 抽离命名路由为单独文件

main.dart

import 'package:flutter/material.dart';

// import 'tabs/Tabs.dart';
import 'package:app03/routers/Routers.dart';

import 'res/listData.dart';

void main() {
  runApp(new MyApp());
}

// 自定义组件
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      // Scaffold 定义导航头部和页面主要内容
      // home: TabsPage(),
      initialRoute: '/', // 抽离 tabs 到路由,需要配置 initialRoute
      onGenerateRoute: onGenerateRoute,
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
    );
  }
}

Routers.dart

import 'package:flutter/material.dart';

import 'package:app03/tabs/Tabs.dart';
import 'package:app03/pages/home/Detail.dart';
import 'package:app03/pages/home/FormPage.dart';

final Map<String, Function> routes = {
  '/': (context) => TabsPage(),
  '/detail': (context) => Detail(), // 2 根据组件构造函数参数,传递路由参数
  '/form': (context, {arguments}) => FormPage(arguments: arguments),
};

var onGenerateRoute = (RouteSettings settings) {
  print('-------${settings.arguments}');
  // 统一处理
  final String name = settings.name;
  final Function pageContentBuilder = routes[name];
  if (pageContentBuilder != null) {
    if (settings.arguments != null) {
      final Route route = MaterialPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      final Route route =
          MaterialPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
};

Tabs.dart(Tabs 组件不变,还是原来的代码)

import 'package:flutter/material.dart';

import 'package:app03/pages/home/HomePage.dart';
import 'package:app03/pages/category/CategoryPage.dart';
import 'package:app03/pages/settings/SettingsPage.dart';

class TabsPage extends StatefulWidget {
  TabsPage({Key key}) : super(key: key);
  @override
  _TabsPageState createState() => _TabsPageState();
}

class _TabsPageState extends State<TabsPage> {
  int currentIndex = 0;
  List listTabs = [
    HomePage(),
    CategoryPage(),
    SettingsPage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('flutter 标题'),
      ),
      body: this.listTabs[this.currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: this.currentIndex,
        iconSize: 30.0,
        type: BottomNavigationBarType.fixed,
        onTap: (index) {
          setState(() {
            this.currentIndex = index;
          });
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('首页'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            title: Text('分类'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            title: Text('设置'),
          ),
        ],
      ),
    );
  }
}

目录结构

5 替换路由和根路由

CategoryPage.dart (tab 页面进入新的 register 页面)

import 'package:flutter/material.dart';

class CategoryPage extends StatefulWidget {
  CategoryPage({Key key}) : super(key: key);

  @override
  _CategoryPageState createState() => _CategoryPageState();
}

class _CategoryPageState extends State<CategoryPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          Text('Category...'),
          SizedBox(
            height: 30,
          ),
          RaisedButton(
            child: Text('go to 注册'),
            onPressed: () {
              Navigator.pushNamed(context, '/registerFirst');
            },
          )
        ],
      ),
    );
  }
}

RegisterFirst.dart

import 'package:flutter/material.dart';

class RegisterFirstPage extends StatefulWidget {
  RegisterFirstPage({Key key}) : super(key: key);

  @override
  _RegisterFirstPageState createState() => _RegisterFirstPageState();
}

class _RegisterFirstPageState extends State<RegisterFirstPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(
          title: Text('注册'),
        ),
        body: Column(
          children: <Widget>[
            SizedBox(height: 100, width: 50),
            Text('注册步骤一'),
            RaisedButton(
              child: Text('下一步'),
              onPressed: () {
                Navigator.of(context).pushNamed("/registerSecond"); // 普通方式跳转
                // Navigator.of(context).pushReplacementNamed(
                //     "/registerSecond"); // 替换路由,Second 路由会替换该 First 路由,所以 Second 返回上一步,就是返回之前 First 路由的上一步。
              },
            )
          ],
        ),
      ),
    );
  }
}

RegisterSecond.dart(替换路由跳转)

import 'package:flutter/material.dart';

class RegisterSecondPage extends StatefulWidget {
  RegisterSecondPage({Key key}) : super(key: key);

  @override
  _RegisterSecondPageState createState() => _RegisterSecondPageState();
}

class _RegisterSecondPageState extends State<RegisterSecondPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(
          title: Text('注册'),
        ),
        body: Column(
          children: <Widget>[
            SizedBox(height: 100, width: 50),
            Text('注册步骤二'),
            RaisedButton(
              child: Text('下一步'),
              onPressed: () {
                Navigator.of(context).pushNamed("/registerThree");
              },
            )
          ],
        ),
      ),
    );
  }
}

RegisterThree.dart(根路由跳转)

import 'package:flutter/material.dart';

import 'package:app03/tabs/Tabs.dart';

class RegisterThreePage extends StatefulWidget {
  RegisterThreePage({Key key}) : super(key: key);

  @override
  _RegisterThreePageState createState() => _RegisterThreePageState();
}

class _RegisterThreePageState extends State<RegisterThreePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(
          title: Text('注册'),
        ),
        body: Column(
          children: <Widget>[
            SizedBox(height: 100, width: 50),
            Text('注册步骤三'),
            RaisedButton(
              child: Text('确定'),
              onPressed: () {
                Navigator.of(context).pushAndRemoveUntil(
                    // 返回到指定到根路由
                    new MaterialPageRoute(builder: (context) => new TabsPage()),
                    (route) => route == null);
              },
            )
          ],
        ),
      ),
    );
  }
}

  • 扩展上面的例子,新增传递 Tabs 参数
RegisterThree.dart

import 'package:flutter/material.dart';

import 'package:app03/tabs/Tabs.dart';

class RegisterThreePage extends StatefulWidget {
  RegisterThreePage({Key key}) : super(key: key);

  @override
  _RegisterThreePageState createState() => _RegisterThreePageState();
}

class _RegisterThreePageState extends State<RegisterThreePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(
          title: Text('注册'),
        ),
        body: Column(
          children: <Widget>[
            SizedBox(height: 100, width: 50),
            Text('注册步骤三'),
            RaisedButton(
              child: Text('确定'),
              onPressed: () {
                Navigator.of(context).pushAndRemoveUntil(
                    // 返回到指定到根路由
                    new MaterialPageRoute(
                        builder: (context) => new TabsPage(index: 1)), // !!!
                    (route) => route == null);
              },
            )
          ],
        ),
      ),
    );
  }
}

Tabs.dart

import 'package:flutter/material.dart';

import 'package:app03/pages/home/HomePage.dart';
import 'package:app03/pages/category/CategoryPage.dart';
import 'package:app03/pages/settings/SettingsPage.dart';

class TabsPage extends StatefulWidget {
  final int index;
  TabsPage({Key key, this.index = 0}) : super(key: key);
  @override
  _TabsPageState createState() => _TabsPageState(this.index);
}

class _TabsPageState extends State<TabsPage> {
  int currentIndex = 0;

  _TabsPageState(index) {
    this.currentIndex = index;
  }

  List listTabs = [
    HomePage(),
    CategoryPage(),
    SettingsPage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('flutter 标题'),
      ),
      body: this.listTabs[this.currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: this.currentIndex,
        iconSize: 30.0,
        type: BottomNavigationBarType.fixed,
        onTap: (index) {
          setState(() {
            this.currentIndex = index;
          });
        },
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('首页'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            title: Text('分类'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            title: Text('设置'),
          ),
        ],
      ),
    );
  }
}

相关文章

网友评论

      本文标题:Flutter(十三):路由

      本文链接:https://www.haomeiwen.com/subject/ayjvfktx.html