Skip to content

路由管理 ​

一、静态路由 ​

使用 pushNamed 跳转

1. 新建一个页面 search.dart ​

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

class Search extends StatelessWidget {
  const Search({super.key});

  @override
  Widget build(BuildContext context) {
    var arguments = ModalRoute.of(context)?.settings.arguments;
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text(arguments as String),
            ),
            body: ElevatedButton(
                onPressed: () {
                  Navigator.pop(context, 'pop路由返回值');
                },
                child: const Text("返回"))));
  }
}

2. 修改 main.dart ​

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

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: {
        '/Search': (context) => const Search(),
      },
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter Demo'),
        ),
        body: const Home(),
      ),
    );
  }
}

class Home extends StatelessWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
        onPressed: () async {
          var result = await Navigator.pushNamed(context, '/Search',
              arguments: '我是命名路由参数');
          //输出pop跳转返回结果
          print("路由返回值: $result");
        },
        child: const Text("点击转跳"));
  }
}

不能直接在 body 属性上注册路由进行跳转

二、动态路由 ​

动态路由无需在 MaterialApp 内的 routes 中注册即可直接使用

两种跳转方法:push,pop

1. 传参 ​

dart
ElevatedButton(
    onPressed: () async {
      var result = await Navigator.push(
          context,
          MaterialPageRoute(
              builder: (context) => const Search(
                    title: '路由传值',
                  )));
      //输出pop跳转返回结果
      print("路由返回值: $result");
    },
    child: const Text("点击转跳"))

2. 接参 ​

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

class Search extends StatelessWidget {
  final String title;

  const Search({super.key, required this.title});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text(title),
            ),
            body: ElevatedButton(
                onPressed: () {
                  Navigator.of(context).pop('pop路由返回值');
                },
                child: const Text("返回"))));
  }
}

有两种方式可以返回到上一页;第一种方式是直接点击导航栏返回箭头,第二种方式是点击页面中的「返回」按钮。这两种返回方式的区别是前者不会返回数据给上一个路由,而后者会

三、路由生成钩子(onGenerateRoute) ​

通过 onGenerateRoute 控制页面权限

原理:onGenerateRoute 在打开命名路由时可能会被调用,之所以说可能,是因为当调用 Navigator.pushNamed(...) 打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的 builder 函数来生成路由组件;如果路由表中没有注册,才会调用 onGenerateRoute 来生成路由

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

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        onGenerateRoute: (RouteSettings settings) {
          print('dayin$settings');
          //可以控制生成路由,做鉴权处理
          final Route route = MaterialPageRoute(
              builder: (context) => const DetailScreen(id: '2'));
          return route;
        },
        home: const Login());
  }
}

class Login extends StatelessWidget {
  const Login({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: TextButton(
          child: const Text('View Details'),
          onPressed: () {
            Navigator.pushNamed(
              context,
              '/home',
            );
          },
        ),
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  final String id;

  const DetailScreen({
    super.key,
    required this.id,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Viewing details for item $id'),
            TextButton(
              child: const Text('Pop!'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
          ],
        ),
      ),
    );
  }
}

四、路由懒加载 ​

通过 deferred as 关键字将一个普通页面变成 deferred-components,然后在路由打开时通过 libraryFuture 加载后渲染页面

dart
//使用deferred as关键字
import 'search.dart' deferred as controller_demo_page;

//定义一个包裹组件
class ContainerAsyncRouterPage extends StatelessWidget {
  final Future libraryFuture;

  final WidgetBuilder child;

  ContainerAsyncRouterPage(this.libraryFuture, this.child);

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: libraryFuture,
        builder: (c, s) {
          if (s.connectionState == ConnectionState.done) {
            if (s.hasError) {
              return Scaffold(
                appBar: AppBar(),
                body: Container(
                  alignment: Alignment.center,
                  child: Text(
                    'Error: ${s.error}',
                    style: TextStyle(color: Colors.red),
                  ),
                ),
              );
            }
            return child.call(context);
          }
          return Scaffold(
            appBar: AppBar(),
            body: Container(
              alignment: Alignment.center,
              child: CircularProgressIndicator(),
            ),
          );
        });
  }
}

//修改router
Map<String, WidgetBuilder> router = {
  'search': (context) {
    return ContainerAsyncRouterPage(controller_demo_page.loadLibrary(),
        (context) {
      return controller_demo_page.DetailScreen();
    });
  }
};

运行 flutter build web,在 build/web 中查看文件