【Flutter】路由详解

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:Flutter学习
🌠 首发时间:2024年5月27日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾

路由介绍

路由,通俗地讲就是页面跳转。在 Flutter 中,我们通过 Navigator 组件来管理路由导航, Navigator 组件中提供了管理堆栈的方法。如:Navigator.push 跳转到某个路由和 Navigator.pop 返回到某个路由

Flutter 中给我们提供了两种配置路由跳转的方式:

  1. 普通路由
  2. 命名路由

普通路由

举例:比如我们现在想从 HomePage 组件跳转到 SearchPage 组件,应该如何使用普通路由实现呢?

  1. 我们先在 pages 目录下简单写一个 search.dart

    import 'package:flutter/material.dart';
    
    class SearchPage extends StatefulWidget {
      const SearchPage({super.key});
    
      
      State<SearchPage> createState() => _SearchPageState();
    }
    
    class _SearchPageState extends State<SearchPage> {
      
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("搜索页面"),
          ),
          body: const Center(
            child: Text("搜索页面"),
          ),
        );
      }
    }
    
  2. home.dart 中引入 search.dart

    import '../search.dart';
    
  3. HomePage 中通过下面方法跳转

    import 'package:flutter/material.dart';
    import '../search.dart';
    
    class HomePage extends StatefulWidget {
      const HomePage({super.key});
    
      
      State<HomePage> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      
      Widget build(BuildContext context) {
        return Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () {
                  Navigator.of(context).push(	//调用push
                    MaterialPageRoute(builder: (context) {
                      return const SearchPage();
                    }),
                  );
                },
                child: const Text("跳转到搜索页面"),
              ),
            ],
          ),
        );
      }
    }
    
  4. 点击按钮,就会自动跳转到搜索页面

    在这里插入图片描述

普通路由跳转传值

跳转传值的意思是在跳转页面的同时传一些值给要跳转的页面,比如页面标题什么的。

我们在 search.dart 中添加一个变量 title 来接收传值,并将其设置为页面导航栏的标题,同时,我们还增加了一个可以返回上个页面的浮动按钮

import 'package:flutter/material.dart';

class SearchPage extends StatefulWidget {
  final String title; //用于接收传值
  const SearchPage({super.key, required this.title});

  
  State<SearchPage> createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title), //通过widget.来调用传过来的值
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          //返回到上一页
          Navigator.pop(context);
        },
        child: const Icon(Icons.home),
      ),
      body: const Center(
        child: Text("搜索页面"),
      ),
    );
  }
}

当然,在跳转页面的时候就必须传入值了

在这里插入图片描述

命名路由

当跳转的页面多了之后,为了方便管理这些页面,这个时候我们就需要用到命名路由。

命名路由的使用很简单,具体步骤如下:

  1. main.dart 中引入项目中所有需要跳转的页面,引入后,在其它文件中就不用再引入了,可以直接使用。比如我们有 search.dartform.dart 两个页面需要跳转:

    import './pages/search.dart';
    import './pages/form.dart';
    

    两个页面除了名字都是一样的

    import 'package:flutter/material.dart';
    
    class SearchPage extends StatefulWidget {
      const SearchPage({super.key});
    
      
      State<SearchPage> createState() => _SearchPageState();
    }
    
    class _SearchPageState extends State<SearchPage> {
      
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("搜一搜"),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              //返回到上一页
              Navigator.pop(context);
            },
            child: const Icon(Icons.home),
          ),
          body: const Center(
            child: Text("搜索页面"),
          ),
        );
      }
    }
    
  2. main.dart 中配置所有路由和初始路由,此时我们不用再配置 home 属性

    import 'package:flutter/material.dart';
    import 'pages/tabs.dart';
    import './pages/search.dart';
    import './pages/form.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          debugShowCheckedModeBanner: false,
          initialRoute: "/",
          routes: {
            "/": (context) => const Tabs(),
            "/search": (context) => const SearchPage(),
            "/form": (context) => const FormPage(),
          },
        );
      }
    }
    

    这两种书写方式的效果是一样的

    "/form": (context) => const FormPage(title: "表单")
    
    "/form": (context) {
      return const FormPage(title: "表单");
    }
    
  3. 然后我们在 home.dart 中进行页面的跳转,不用引入,而且只需要一行代码

    import 'package:flutter/material.dart';
    
    class HomePage extends StatefulWidget {
      const HomePage({super.key});
    
      
      State<HomePage> createState() => _HomePageState();
    }
    
    class _HomePageState extends State<HomePage> {
      
      Widget build(BuildContext context) {
        return Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () {
                  Navigator.pushNamed(context, "/search");
                },
                child: const Text("命名路由跳转搜索页面"),
              ),
              const SizedBox(height: 30),
              ElevatedButton(
                onPressed: () {
                  Navigator.pushNamed(context, "/form");
                },
                child: const Text("命名路由跳转表单页面"),
              ),
            ],
          ),
        );
      }
    }
    

命名路由跳转传值

具体步骤:

  1. 定义路由
  2. 配置 onGenerateRoute
  3. 定义页面接收 arguments 传参
  4. 跳转页面实现传参
  5. 打印验证传值是否成功

完整代码:

main.dart

import 'package:flutter/material.dart';
import 'pages/tabs.dart';
import './pages/search.dart';
import './pages/form.dart';

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

class MyApp extends StatelessWidget {
  //1. 定义路由
  Map routes = {
    "/": (context) => const Tabs(),
    "/search": (context, {arguments}) =>
        SearchPage(arguments: arguments), //定义arguments后, 需要传入arguments
    "/form": (context) => const FormPage(),
  };
  MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      debugShowCheckedModeBanner: false,
      initialRoute: "/",
      //2. 配置onGenerateRoute,固定写法
      onGenerateRoute: (settings) {
        // 统一处理
        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;
          }
        }
        return null;
      },
    );
  }
}

search.dart

import 'package:flutter/material.dart';

class SearchPage extends StatefulWidget {
  //3. 定义页面接收arguments传参
  final Map arguments;
  const SearchPage({super.key, required this.arguments});

  
  State<SearchPage> createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  
  void initState() {
    super.initState();
    //5. 打印传过来的值
    print(widget.arguments);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("搜一搜"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          //返回到上一页
          Navigator.pop(context);
        },
        child: const Icon(Icons.home),
      ),
      body: const Center(
        child: Text("搜索页面"),
      ),
    );
  }
}

home.dart

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () {
              //4. 跳转页面实现传参
              Navigator.pushNamed(context, "/search", arguments: {
                "title": "搜索页面",
                "aid": 20,
              });
            },
            child: const Text("命名路由跳转传值"),
          ),
          const SizedBox(height: 30),
          ElevatedButton(
            onPressed: () {
              Navigator.pushNamed(context, "/form");
            },
            child: const Text("命名路由跳转表单页面"),
          ),
        ],
      ),
    );
  }
}

启动项目后,当我们点击第一个按钮时,终端打印出我们传递过去的参数,即为成功:

在这里插入图片描述

将命名路由单独抽离

  1. lib 目录下新建 routers 文件夹,在文件夹下新建文件 router.dart,然后将 main.dart 中和路由有关的代码复制过来

    import 'package:flutter/material.dart';
    import '../pages/tabs.dart';
    import '../pages/search.dart';
    import '../pages/form.dart';
    
    //1. 定义路由
    final Map routes = {
      "/": (context) => const Tabs(),
      "/search": (context, {arguments}) =>
          SearchPage(arguments: arguments), //定义arguments后, 需要传入arguments
      "/form": (context) => const FormPage(),
    };
    
    //2. 配置onGenerateRoute,固定写法
    var onGenerateRoute = (settings) {
      // 统一处理
      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;
        }
      }
      return null;
    };
    
  2. 修改 main.dart

    import 'package:flutter/material.dart';
    import './routers/router.dart';	//引入
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          debugShowCheckedModeBanner: false,
          initialRoute: "/",
          onGenerateRoute: onGenerateRoute,
        );
      }
    }
    

返回上一级路由

Navigator.of(context).pop();

替换路由

一般在一个页面跳转后,我们点击返回按钮,只能返回到上一级页面。如果我们想让其直接返回到上上级页面,跳过上一级页面,这个时候就需要用到替换路由,我们需要将被跳过的页面中的跳转语句改为类似如下:

Navigator.of(context).pushReplacementNamed('/registerSecond');

返回到根路由

当跳转页面太多的时候,替换路由并不能让我们在某个页面直接返回到最开始的那个页面,这个时候我们就需要用到跟路由的知识。

首先,我们需要在需要跳转的页面中引入最开始那个页面,然后将其中的跳转语句改为类似如下:

//返回到根页面
Navigator.of(context).pushAndRemoveUntil(
    MaterialPageRoute(builder: (BuildContext context) {
  return const Tabs();
}), (route) => false);

Android和Ios使用同样风格的路由跳转

Material 组件库中提供了一个 MaterialPageRoute 组件,它可以使用和平台风格一致的路由切换动画,如在 iOS 上会左右滑动切换,而在 Android 上会上下滑动切换,CupertinoPageRouteCupertino 组件库提供的 iOS 风格的路由切换组件,如果在 Android 上也想使用左右切换风格,我们可以使用 CupertinoPageRoute

具体步骤如下:

  1. router.dart 中删掉 import 'package:flutter/material.dart';,然后引入 Cupertino 组件,即 import 'package:flutter/cupertino.dart';
  2. router.dart 代码中的 MaterialPageRoute 改为 CupertinoPageRoute 即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序喵正在路上

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值