跳至主要內容

Flutter路由

xiaoye大约 6 分钟FlutterRouterFlutterFlutterRouter

官网地址:选择你的开发平台,开始使用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutteropen in new window

文档地址:第二版序 | 《Flutter实战·第二版》 (flutterchina.club)open in new window

FlutterRouter

1、Flutter中的路由

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

1.1、基本路由

1.1.1、引入你要跳转的页面

基本陆路由中页面跳转案例

import 'package:flutter/material.dart';

// 引入要跳转的页面
import 'package:bangda/components/YStateComponents/YRouterPage1.dart';

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

  
  State<OrderPage> createState() => _OrderPageState();
}

class _OrderPageState extends State<OrderPage> {
  
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
          onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) {
              return const YRouterPage1(); //返回你要跳转的页面
            }));
          },
          child: const Text('跳转到新页面')),
    );
  }
}

1.1.2、跳转传值

  1. 在被跳转页面定义一个变量来接收参数
    import 'package:flutter/material.dart';
    
    class YRouterPage1 extends StatefulWidget {
      final String title;
      final String content;
      final Object options;
      const YRouterPage1(
          {super.key,
          this.title = "标题",
          this.content = "内容",
          required this.options});
      
      
      State<YRouterPage1> createState() => _YRouterPage1State();
    }
    
    class _YRouterPage1State extends State<YRouterPage1> {
      
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text(widget.title)), //引用传来的标题
          body: Center(
            child: Column(
              children: [
                Text(widget.content),
                Text('姓名:${widget.options}')
              ], //引用传来的内容
            ),
          ),
        );
      }
    }
    
  2. 要跳转的页面传入参数

    Navigator.of(context).push(MaterialPageRoute(builder: (context) {
        return const YRouterPage1(
            //传参
            title: '今天吃啥子',
            content: '罗非鱼!',
            options: {
                "name": "张三",
                "age": 18,
            },
        ); //返回你要跳转的页面并且传参
    })
    

1.2、命名路由

当项目比较大时,使用命名路由统一管理

1.2.1、直接抽离一个routers文件来单独管理路由

routers/index.dart

import 'package:flutter/material.dart';
// 引入路由列表
import 'package:bangda/pages/tabbar/index.dart';
import 'package:bangda/components/YRouters/Search.dart';
import 'package:bangda/components/YRouters/Details.dart';
import 'package:bangda/components/YRouters/YForm.dart';
import 'package:bangda/components/YRouters/YShop.dart';

// 定义路由
Map routes = {
  "/": (context) => const TabBars(),
  "/search": (context) => const RouterSerachPage(),
  "/details": (context) => const RouterDetailsPage(),
  //传参给YFormPage页面
  "/form": (context, {arguments}) => YFormPage(arguments: arguments),
  "/shop": (context, {arguments}) => YshopPage(arguments: arguments),
};

// 定义onGenerateRoute  固定写法
var onGenerateRoute = (RouteSettings settings) {
// 相当于跳转路由时的中间件   可以打印settings来做一些操作  比如拦截或者权限判断

  // 跳转时执行这里的方法
  final String? name = settings.name; //获取settings.name路由名称
  final Function? pageContentBuilder =
      routes[name]; //赋值跳转的路由给pageContentBuilder
  if (pageContentBuilder != null) {
    //如果有arguments就传入arguments
    if (settings.arguments != null) {
      final Route route = MaterialPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      //没有arguments就直接跳转
      final Route route =
          MaterialPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
  return null;
};

1.2.2、在main.dart中使用路由

import 'package:flutter/material.dart';
// tabbar
// 引入路由
import 'package:bangda/routes/index.dart';

void main() {
  return runApp(MaterialApp(
    debugShowCheckedModeBanner: false, //去掉右上角的debug图标
    theme: ThemeData(primarySwatch: Colors.blue, primaryColor: Colors.blue),
    // home: const TabBars(),//使用路由需要去掉默认的home,并由initialRoute来设置默认页面
    initialRoute: "/", //初始化路由,每次打开直接定位到routers中的/,也可以设置为其它页面
    onGenerateRoute: onGenerateRoute,
  ));
}

1.2.3、实现传参

  1. 路由中定义(routers/index.dart)

    //传参给YFormPage页面
      "/form": (context, {arguments}) => YFormPage(arguments: arguments),
      "/shop": (context, {arguments}) => YshopPage(arguments: arguments),
    
  2. 页面跳转使用

    • 固定写法:/form为你配置的页面,arguments为参数对象
    import 'package:flutter/material.dart';
    
    class OrderPage extends StatefulWidget {
      const OrderPage({super.key});
    
      
      State<OrderPage> createState() => _OrderPageState();
    }
    
    class _OrderPageState extends State<OrderPage> {
      
      Widget build(BuildContext context) {
        return Center(
          child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
            const Text('命名路由跳转跳转新页面传参:'),
            ElevatedButton(
                onPressed: () {
                  Navigator.pushNamed(context, '/search');
                },
                child: const Text('跳转到Search')),
            const SizedBox(
              height: 20,
            ),
            const Text('通过命名路由跳转传参:'),
            ElevatedButton(
                onPressed: () {
                  Navigator.pushNamed(context, '/form', arguments: {
                    "name": "py",
                    "age": 23,
                  });
                },
                child: const Text('跳转到表单')),
            ElevatedButton(
                onPressed: () {
                  Navigator.pushNamed(context, '/shop', arguments: {
                    "name": "我是命名路由传过来的",
                    "age": 23,
                  });
                },
                child: const Text('跳转到shop'))
          ]),
        );
      }
    }
    
  3. 接收参数页面

    import 'package:flutter/material.dart';
    
    class YFormPage extends StatefulWidget {
      // 定义接收参数
      final Map arguments;
      const YFormPage({super.key, required this.arguments});
    
      
      State<YFormPage> createState() => _YFormPageState();
    }
    
    class _YFormPageState extends State<YFormPage> {
      
      void initState() {
        // TODO: implement initState
        super.initState();
        print(widget.arguments);
      }
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('form')),
          body: Center(
            child: Column(children: [Text('参数${widget.arguments}')]),
          ),
        );
      }
    }
    

1.3、返回上一级路由

Navigator.of(context).pop();

1.4、替换路由(重定向)

从当前页面跳转到search页面,然后从search页面使用pushReplacementNamed跳转到details页面,此时点击返回,则会返回到search页面

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

1.5、返回到根路由

比如我们从用户中心跳转到A页面,然后从A页面跳转到B页面,然后从B跳转到了C页面。这个时候我们想的是C注册成功后返回到用户中心。 这个时候就用到了返回到根路由的方法。

  • 可以通过传参来控制返回到tabbar页面的激活index
Navigator.of(context).pushAndRemoveUntil(
    MaterialPageRoute(builder: (BuildContext context) {
    return const TabBars(index: 2,);//返回的页面,这里是返回到tabbar页面传参可控制tabbar页面的index  
}), (route) => false);
  • 在tabbar页面接收index
import 'package:flutter/material.dart';

// 引入tabbar对应页面
import '../home/home_page.dart';
import '../user/user_page.dart';
import '../order/order_page.dart';

// 自定义底部导航
class TabBars extends StatefulWidget {
  final int index; //这是传来的index返回梗路由时传来的index
  const TabBars({super.key, this.index = 0});

  
  State<TabBars> createState() => _TabBarsState();
}

class _TabBarsState extends State<TabBars> {
  // 所有tabbar列表
  final List<Widget> _pageList = const [
    HomePage(),
    OrderPage(),
    UserPage(),
  ];
  int _currentTabs = 0; // 当前激活的tabbar
  
  void initState() {
    // TODO: implement initState
    super.initState();
    //初始化_currentTabs为index,index默认为0,如果传了就使用index职位索引
    _currentTabs = widget.index;
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter App'),
        backgroundColor: Colors.deepOrange,
      ),
      body: _pageList[_currentTabs], //激活index对应的_pageList
      bottomNavigationBar: BottomNavigationBar(
        iconSize: 24, //底部菜单的大小默认24
        fixedColor: Colors.red, //选中的颜色
        currentIndex: _currentTabs, //当前激活index
        // type: BottomNavigationBarType.fixed, //如果超过三个tab需要设置为fixed来固定
        onTap: (e) {
          setState(() {
            _currentTabs = e; //重新设置激活的index,重新build
          });
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.article),
            label: '订单',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
    );
  }
}

当我们每次打开页面时直接定位到某个页面只需要设置

1.6、Android 和 Ios 使用同样风格的路由跳转动画风格

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

1.6.1、routes/index.dart中引入cupertino.dart

import 'package:flutter/cupertino.dart';

1.6.2、routes/index.dart中MaterialPageRoute改为CupertinoPageRoute

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart'; //路由风格切换未ios使用MaterialPageRoute改为CupertinoPageRoute
// 引入路由列表
import 'package:bangda/pages/tabbar/index.dart';
import 'package:bangda/components/YRouters/Search.dart';
import 'package:bangda/components/YRouters/Details.dart';
import 'package:bangda/components/YRouters/YForm.dart';
import 'package:bangda/components/YRouters/YShop.dart';
import 'package:bangda/components/YRouters/Register1.dart';
import 'package:bangda/components/YRouters/Register2.dart';
import 'package:bangda/pages/login/login_page.dart';

// 定义路由
Map routes = {
  "/": (context) => const TabBars(),
  "/search": (context) => const RouterSerachPage(),
  "/details": (context) => const RouterDetailsPage(),
  //传参给YFormPage页面
  "/form": (context, {arguments}) => YFormPage(arguments: arguments),
  "/shop": (context, {arguments}) => YshopPage(arguments: arguments),
  "/register1": (context) => const registerPage1(),
  "/register2": (context) => const registerPage2(),
  "/login": (context) => const loginPage(), //登陆页
};

// 定义onGenerateRoute  固定写法
var onGenerateRoute = (RouteSettings settings) {
// 相当于跳转路由时的中间件   可以打印settings来做一些操作  比如拦截或者权限判断

  // 跳转时执行这里的方法
  final String? name = settings.name; //获取settings.name路由名称
  final Function? pageContentBuilder =
      routes[name]; //赋值跳转的路由给pageContentBuilder
  if (pageContentBuilder != null) {
    //如果有arguments就传入arguments
    if (settings.arguments != null) {
      final Route route = CupertinoPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      //没有arguments就直接跳转
      final Route route =
          CupertinoPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
  return null;
};

控制台按o切换平台,就可以看到不同平台的路由跳转风格

1.7、全局配置主题

return MaterialApp(
    debugShowCheckedModeBanner: false,//去除debug
    title: 'Flutter Demo',//全局标题
    theme: ThemeData(
        primarySwatch: Colors.blue,
        appBarTheme: const AppBarTheme(
        centerTitle: true,//全局标题居中
   	 )
    ),
    initialRoute: "/",
    onGenerateRoute: onGenerateRoute,
);