Flutter命名路由

1. 基本介绍

Route 在 Flutter 里是极其重要的部分,用来处理页面跳转。本文主要普通路由,命名路由,以及自定义路由等。

2. 基础功能

  • 命名路由 routes
  • 路由跳转 push、pop
  • 初始路由 initialRoute
  • 路由拦截 onGenerateRoute

3. 命名 Route 详解

3.1 容器创建

优雅的编程,我们创建一个 materialapp.dart 文件。

import 'package:flutter/material.dart';

class FMMaterialAppVC extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        body: AAA(),
      ),
      routes: {
        '/bbb': (context) => BBB(),
        '/ccc': (context) => CCC(),
        '/ddd': (context) => DDD(),
      },
    );
  }
}

class AAA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('AAA'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击前往BBB'),
          onPressed: (){
            Navigator.pushNamed(context, '/bbb');
          },
        ),
      ),
    );
  }
}

class BBB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('BBB'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击前往CCC'),
          onPressed: (){
            Navigator.pushNamed(context, '/ccc');
          },
        ),
      ),
    );
  }
}

class CCC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('CCC'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击前往DDD'),
          onPressed: (){
            Navigator.pushNamed(context, '/ddd');
          },
        ),
      ),
    );
  }
}

class DDD extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('DDD'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击回到AAA'),
          onPressed: (){
            Navigator.popUntil(context, (route) => route.isFirst);
          },
        ),
      ),
    );
  }
}

3.2 路由跳转方式之 Push 详解

在上文中,我们使用了 pushNamed 方法,推到一个新的页面。

class AAA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('AAA'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击前往BBB'),
          onPressed: (){
            Navigator.pushNamed(context, '/bbb');
          },
        ),
      ),
    );
  }
}

3.2.1 Navigator.pushNamed

无参数

Navigator.pushNamed(context, '/bbb');

有参数

final datas = {"data": ["1","2","3"]};
Navigator.pushNamed(context, '/bbb', arguments: datas);

3.2.2 Navigator.push

无参数

Navigator.push(
    context,
    MaterialPageRoute(
        builder: (context){
            return BBB();
        }
);

有参数,name 可以用来给路由命名,arguments 用来传递参数

final datas = {"data": ["1","2","3"]};

Navigator.push(
    context,
    MaterialPageRoute(
        builder: (context){
            return BBB();
        },
        settings: RouteSettings(
        name: '/bbb',
        arguments: datas,
        ),
    ),
);

3.2.3 Navigator.of(context).pushNamed

基本用法同上

3.2.4 Navigator.of(context).push

基本用法同上

3.3 路由跳转方式之 Push 进阶

注意:写法大同小异,后续就不在赘述传参方式

3.3.1 pushNamedAndRemoveUntil

例如我们页面从AAA->BBB->CCC->DDD,这样进行页面,但是我们希望 CCC 再使用过后就被销毁。使得页面层级变为 AAA-BBB-DDD。

  • Navigator.pushNamedAndRemoveUntil

如下方代码,我们在 CCC 中来做处理。 我们的页面层级为 AAA->BBB->CCC->DDD,我们在 CCC 中 push 到 DDD 页面,然后从栈顶开始删除,直到这个route.setting.name == '/bbb',也就是销毁 BBB 与 DDD 中间所有的页面。

class CCC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('CCC'),
      ),
      body: _listView(context),
    );
  }

  ListView _listView(BuildContext context){
    return ListView(
      children: [
        ListTile(
          title: Text("Navigator.pushNamed"),
          onTap: (){
            Navigator.pushNamed(context, '/ddd');
          },
        ),
        ListTile(
          title: Text("Navigator.pushNamedAndRemoveUntil"),
          onTap: (){
            Navigator.pushNamed(context, '/ddd');
          },
        ),
        ListTile(
          title: Text("Navigator.of(context).pushNamedAndRemoveUntil"),
          onTap: (){
            Navigator.of(context).pushNamedAndRemoveUntil('/ddd', (route) => route.settings.name == '/ddd');
          },
        ),
        ListTile(
          title: Text("Navigator.pushNamedAndRemoveUntil - current"),
          onTap: (){
            Navigator.of(context).pushNamedAndRemoveUntil('/ddd', (route) => route.isCurrent);
          },
        ),
        ListTile(
          title: Text("Navigator.pushReplacementNamed"),
          onTap: (){
            Navigator.pushReplacementNamed(context, '/ddd');
          },
        ),
        ListTile(
          title: Text("Navigator.of(context).pushReplacementNamed"),
          onTap: (){
            Navigator.of(context).pushReplacementNamed('/ddd');
          },
        ),
        ListTile(
          title: Text("Navigator.pushReplacement"),
          onTap: (){
            Navigator.pushReplacement(context,
              MaterialPageRoute(
                builder: (context){
                  return DDD();
                },
                settings: RouteSettings(
                  name: '/ddd',
                ),
              ),
            );
          },
        ),
        ListTile(
          title: Text("Navigator.of(context).pushReplacement"),
          onTap: (){
            Navigator.of(context).pushReplacement(
              MaterialPageRoute(
                builder: (context){
                  return DDD();
                },
                settings: RouteSettings(
                  name: '/ddd',
                ),
              ),
            );
          },
        ),
        ListTile(
          title: Text("Navigator.popAndPushNamed"),
          onTap: (){
            Navigator.popAndPushNamed(context, '/ddd');
          },
        ),
        ListTile(
          title: Text("Navigator.of(context).popAndPushNamed"),
          onTap: (){
            Navigator.of(context).popAndPushNamed('/ddd');
          },
        ),
      ],
    );
  }
}

3.3.2 pushReplacementNamed

基本用法同上

3.3.3 popAndPushNamed

基本用法同上

3.4 路由跳转方式之 Pop 详解

class DDD extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('DDD'),
      ),
      body: _listView(context),
    );
  }

  ListView _listView(BuildContext context){
    return ListView(
      children: [
        ListTile(
          title: Text('Navigator.pop'),
          onTap: (){
            Navigator.pop(context);
            // final data = {"data":["1","2","3"]};
            // Navigator.pop(context, data);
          },
        ),
        ListTile(
          title: Text('Navigator.pop'),
          onTap: (){
            Navigator.of(context).pop();
          },
        ),
        ListTile(
          title: Text('Navigator.canPop'),
          onTap: (){
            bool canpop = Navigator.canPop(context);
            if (canpop) Navigator.pop(context);
          },
        ),
        ListTile(
          title: Text('Navigator.maybePop'),
          onTap: (){
            Navigator.maybePop(context);
          },
        ),
      ],
    );
  }
}

3.4.1 Navigator.pop

3.4.2 Navigator.of(context).pop

3.4.3 Navigator.canPop

3.4.4 Navigator.of(context).canPop

3.4.5 Navigator.maybePop

3.4.6 Navigator.of(context).maybePop

3.5 路由跳转方式之 Pop 进阶

  • 回到栈顶
Navigator.popUntil(context, (route) => route.isFirst);
  • 回到指定页面
Navigator.popUntil(context, (route) => route.settings.name == '/bbb');
  • 页面堆栈了解
Navigator.popUntil(context, (route) => _lookRoutes(route));
bool _lookRoutes(Route route){
    print(route);
    return route.isFirst;
}

4. 初始路由 initialRoute

我们注释掉 home 属性,使用 initialRoute 来加载页面

  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      // home: Scaffold(
      //   body: AAA(),
      // ),
      initialRoute: '/ccc',
      routes: {
        '/aaa': (context) => AAA(),
        '/bbb': (context) => BBB(),
        '/ccc': (context) => CCC(),
        '/ddd': (context) => DDD(),
      },
    );
  }

5. 未知路由 onUnknownRoute

class FMMaterialAppVC extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (context) => AAA(),
        '/bbb': (context) => BBB(),
        '/ccc': (context) => CCC(),
        '/ddd': (context) => DDD(),
      },
      onUnknownRoute: (setting){
        print(setting);
        return MaterialPageRoute(builder: (context) => AAA());
      },
    );
  }
}

class BBB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('BBB'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击前往CCC'),
          onPressed: (){
            Navigator.pushNamed(context, '/cc');
          },
        ),
      ),
    );
  }
}

6. 路由拦截 onGenerateRoute

class FMMaterialAppVC extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      // home: Scaffold(
      //   body: AAA(),
      // ),
      initialRoute: '/',
      routes: {
        '/': (context) => AAA(),
        '/bbb': (context) => BBB(),
        '/ccc': (context) => CCC(),
        '/ddd': (context) => DDD(),
      },
      // onGenerateInitialRoutes: (string){
      //   return [
      //     MaterialPageRoute(builder: (context) => AAA()),
      //   ];
      // },
      onGenerateRoute: (setting){
        print(setting);
        return MaterialPageRoute(builder: (context) => CCC());
      },
      onUnknownRoute: (setting){
        print(setting);
        return MaterialPageRoute(builder: (context) => AAA());
      },
    );
  }
}

7. 路由拦截独立一个文件

文件目录

import 'package:flutter/material.dart';
import 'package:yuncheng/utils/log_util.dart';

import '../pages/user/login.dart';
import '../pages/user/register.dart';
import '../pages/user/edit_password.dart';

final routes = {
  '/login': (context) => const Login(),
  '/register': (context, {arguments}) => Register(arguments: arguments),
  '/editEassword': (context, {arguments}) => EditPassword(arguments: arguments),
};

// 路由拦截
var onGenerateRoute = (RouteSettings settings) {
  // 统一处理
  final String? name = settings.name;
  LogUtil.v(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;
    }
  }
};

main.dart

import 'package:flutter/material.dart';
import 'package:yuncheng/utils/log_util.dart';
import 'pages/my_bottom_app_bar.dart';
import 'utils/color.dart';
import 'routes/routes.dart';

void main() {
  // 初始化日志系统
  LogUtil.init(tag: "package:yuncheng-utils", isDebug: true);

  runApp(const Myapp());
}

class Myapp extends StatelessWidget {
  const Myapp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "电商系统",
      theme: ThemeData(
        primarySwatch:
            createMaterialColor(const Color.fromARGB(255, 178, 10, 8)),
      ),
      debugShowCheckedModeBanner: false,
      home: const MyBottomAppBar(),
      onGenerateRoute: onGenerateRoute,
    );
  }
}

results matching ""

    No results matching ""