Flutter 路由介绍

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

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

  1. 基本路由
  2. 命名路由

Flutter 中的普通路由使用

比如我们现在想从HomePage组件跳转到SearchPage组件。

1丶 需要在HomPage中引入SearchPage.dart

import '../SearchPage.dart';

2丶在HomePage中通过下面方法跳转

Center(
    child: ElevatedButton(onPressed: (){
        Navigator.of(context).push(
          MaterialPageRoute(builder: (context){
          return const SearchPage();
        })
        );
    }, 
    child: const Text("跳转到搜索页面")),
)
import 'package:flutter/material.dart';
import 'package:flutter_application_1/search.dart';
import 'package:flutter_application_1/user.dart';

import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';

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

  @override
  State<TabsPage> createState() => _TabsPageState();
}

class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
  @override
  int _currentIndex = 0;
  final List _pageList = [
    const HomePage(),
    const CategoryPage(),
    const MessagePage(),
    const SettingPage(),
    const UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(Icons.menu),
          onPressed: (){
            print('menu');
          },
        ),
        title: const Text('Flutter App'),
        actions: [  
          IconButton(
            icon: const Icon(Icons.search),
            onPressed: (){ // 跳转到搜索页面
              print('search');
              Navigator.of(context).push(
                MaterialPageRoute(builder: (BuildContext context){
                  return const SearchPage();
                })
              );
            },
          ),
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: (){
              print('settings');
            },
          ),
          ],
          backgroundColor: Colors.red,

      ),
      body: _pageList[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type 
        fixedColor: Colors.red, // 选中的颜色
        //iconSize: 35, // 图标大小
        onTap: (int index){
          print(index);
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: '分类',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.message),
            label: '消息',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: '设置',
          ),
          // 我的
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
      floatingActionButton: Container(
        width: 60,
        height: 60,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(30),
          color: Colors.white,
        ),
        margin: const EdgeInsets.only(top: 4),
        padding: const EdgeInsets.all(4),
        child: FloatingActionButton(
          onPressed: (){
            setState(() {
              _currentIndex = 2;
            });
          },
          backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
          child: const Icon(Icons.add),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }

}

Flutter 中的普通路由跳转传值


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

import 'form.dart';
import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';

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

  @override
  State<TabsPage> createState() => _TabsPageState();
}

class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
  @override
  int _currentIndex = 0;
  final List _pageList = [
    const HomePage(),
    const CategoryPage(),
    const MessagePage(),
    const SettingPage(),
    const UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(Icons.menu),
          onPressed: (){
            print('menu');
            Navigator.of(context).push(
              MaterialPageRoute(builder: (BuildContext context){
                return const FormPage(title:'我是表单');
              })
            );
          },
        ),
        title: const Text('Flutter App'),
        actions: [  
          IconButton(
            icon: const Icon(Icons.search),
            onPressed: (){
              print('search');
              Navigator.of(context).push(
                MaterialPageRoute(builder: (BuildContext context){
                  return const SearchPage();
                })
              );
            },
          ),
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: (){
              print('settings');
            },
          ),
          ],
          backgroundColor: Colors.red,

      ),
      body: _pageList[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type 
        fixedColor: Colors.red, // 选中的颜色
        //iconSize: 35, // 图标大小
        onTap: (int index){
          print(index);
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: '分类',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.message),
            label: '消息',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: '设置',
          ),
          // 我的
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
      floatingActionButton: Container(
        width: 60,
        height: 60,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(30),
          color: Colors.white,
        ),
        margin: const EdgeInsets.only(top: 4),
        padding: const EdgeInsets.all(4),
        child: FloatingActionButton(
          onPressed: (){
            setState(() {
              _currentIndex = 2;
            });
          },
          backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
          child: const Icon(Icons.add),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }

}

Flutter 中的命名路由

import 'package:flutter/material.dart';
import 'package:flutter_application_1/tabs.dart';
import 'home.dart';
import 'search.dart';
import 'form.dart';
import 'news.dart';
// import 'listData.dart';

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

class MyApp extends StatelessWidget {
  // ignore: use_key_in_widget_constructors
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home:  HomePage(), 
      // home: const Main(),
      initialRoute: '/',
      routes: (
        {
          '/': (context) => const Main(),
          '/search': (context) => const SearchPage(),
          '/form': (context) => const FormPage(title:'我是表单'),
          '/news': (context){
            return const NewsPage();
          },
        }

      ),
    );
  }
}
class Main extends StatefulWidget {

  const Main({ Key? key }) : super(key: key);

  @override
  // ignore: library_private_types_in_public_api
  _MainState createState() => _MainState();
}

class _MainState extends State<Main> {

  @override
  Widget build(BuildContext context) {
    return const TabsPage();
  }
}
import 'package:flutter/material.dart';
import 'package:flutter_application_1/search.dart';
import 'package:flutter_application_1/user.dart';

import 'form.dart';
import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';

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

  @override
  State<TabsPage> createState() => _TabsPageState();
}

class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
  @override
  int _currentIndex = 0;
  final List _pageList = [
    const HomePage(),
    const CategoryPage(),
    const MessagePage(),
    const SettingPage(),
    const UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(Icons.menu),
          onPressed: (){
            print('menu');
            Navigator.of(context).push(
              MaterialPageRoute(builder: (BuildContext context){
                return const FormPage(title:'我是表单');
              })
            );
          },
        ),
        title: const Text('Flutter App'),
        actions: [  
          IconButton(
            icon: const Icon(Icons.search),
            onPressed: (){
              print('search');
              // Navigator.of(context).push(
              //   MaterialPageRoute(builder: (BuildContext context){
              //     return const SearchPage();
              //   })
              // );
              Navigator.of(context).pushNamed('/search'); // 命名路由跳转
            },
          ),
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: (){
              print('settings');
            },
          ),
          ],
          backgroundColor: Colors.red,

      ),
      body: _pageList[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type 
        fixedColor: Colors.red, // 选中的颜色
        //iconSize: 35, // 图标大小
        onTap: (int index){
          print(index);
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: '分类',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.message),
            label: '消息',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: '设置',
          ),
          // 我的
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
      floatingActionButton: Container(
        width: 60,
        height: 60,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(30),
          color: Colors.white,
        ),
        margin: const EdgeInsets.only(top: 4),
        padding: const EdgeInsets.all(4),
        child: FloatingActionButton(
          onPressed: (){
            setState(() {
              _currentIndex = 2;
            });
          },
          backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
          child: const Icon(Icons.add),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }

}

Flutter 中的命名路由传值

1丶在main.dart中配置路由

import 'package:flutter/material.dart';
import 'package:flutter_application_1/tabs.dart';
import 'home.dart';
import 'search.dart';
import 'form.dart';
import 'news.dart';
// import 'listData.dart';

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

class MyApp extends StatelessWidget {
  // 配置路由
  Map router = {
    '/': (context) => const Main(),
    '/search': (context) => const SearchPage(),
    '/form': (context, {arguments}) => FormPage(arguments: arguments),
    '/news': (context){
      return const NewsPage();
    },
  };

  // ignore: use_key_in_widget_constructors
  MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home:  HomePage(), 
      // home: const Main(),
      initialRoute: '/',
      // 配置onGenerateRoute 固定写法
      onGenerateRoute: (RouteSettings settings){
        final String? name = settings.name;
        final Function pageContentBuilder = router[name] as Function;
        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;
      }
    );
  }
}
class Main extends StatefulWidget {

  const Main({ Key? key }) : super(key: key);

  @override
  // ignore: library_private_types_in_public_api
  _MainState createState() => _MainState();
}

class _MainState extends State<Main> {

  @override
  Widget build(BuildContext context) {
    return const TabsPage();
  }
}

2丶在form.dart中接收参数

import 'package:flutter/material.dart';


class FormPage extends StatefulWidget {
  final Map arguments;
  const FormPage({super.key, required this.arguments,});

  @override
  State<FormPage> createState() => _FormPageState();
}

class _FormPageState extends State<FormPage> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    print(widget.arguments);
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.arguments['title']),
      ),
      body: const Center(
        child: Text('表单'),
      ),
    );;
  }
}

3丶在home.dart中跳转传值

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

import 'form.dart';
import 'home.dart';
import 'category.dart';
import 'setting.dart';
import 'message.dart';

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

  @override
  State<TabsPage> createState() => _TabsPageState();
}

class _TabsPageState extends State<TabsPage> with SingleTickerProviderStateMixin {
  @override
  int _currentIndex = 0;
  final List _pageList = [
    const HomePage(),
    const CategoryPage(),
    const MessagePage(),
    const SettingPage(),
    const UserPage(),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: const Icon(Icons.menu),
          onPressed: (){
            print('menu');
            Navigator.pushNamed(context, '/form',arguments: {
              'title':'我是表单'
            }); // 命名路由传参跳转
          },
        ),
        title: const Text('Flutter App'),
        actions: [  
          IconButton(
            icon: const Icon(Icons.search),
            onPressed: (){
              print('search');
              // Navigator.of(context).push(
              //   MaterialPageRoute(builder: (BuildContext context){
              //     return const SearchPage();
              //   })
              // );
              Navigator.of(context).pushNamed('/search');
            },
          ),
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: (){
              print('settings');
            },
          ),
          ],
          backgroundColor: Colors.red,

      ),
      body: _pageList[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        type: BottomNavigationBarType.fixed, // 如果有4个以上的按钮,必须设置type 
        fixedColor: Colors.red, // 选中的颜色
        //iconSize: 35, // 图标大小
        onTap: (int index){
          print(index);
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: '分类',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.message),
            label: '消息',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.settings),
            label: '设置',
          ),
          // 我的
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
      floatingActionButton: Container(
        width: 60,
        height: 60,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(30),
          color: Colors.white,
        ),
        margin: const EdgeInsets.only(top: 4),
        padding: const EdgeInsets.all(4),
        child: FloatingActionButton(
          onPressed: (){
            setState(() {
              _currentIndex = 2;
            });
          },
          backgroundColor: _currentIndex == 2 ? Colors.red :Colors.blue,
          child: const Icon(Icons.add),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }

}

Flutter 中的命名路由单独抽离到一个文件中

1丶新建一个router.dart文件

import 'package:flutter/material.dart';

import '../form.dart';
import '../main.dart';
import '../news.dart';
import '../search.dart';

// 配置路由
  Map router = {
    '/': (context) => const Main(),
    '/search': (context) => const SearchPage(),
    '/form': (context, {arguments}) => FormPage(arguments: arguments),
    '/news': (context){
      return const NewsPage();
    },
  };
  // 配置onGenerateRoute 固定写法
  var onGenerateRoute = (RouteSettings settings){
    final String? name = settings.name;
    final Function pageContentBuilder = router[name] as Function;
    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中引入router.dart文件

import 'package:flutter/material.dart';
import 'package:flutter_application_1/tabs.dart';
import 'home.dart';
import 'router/routers.dart';
import 'search.dart';
import 'form.dart';
import 'news.dart';
// import 'listData.dart';

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

class MyApp extends StatelessWidget {


  // ignore: use_key_in_widget_constructors
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // home:  HomePage(), 
      // home: const Main(),
      initialRoute: '/',
      onGenerateRoute: onGenerateRoute,
    );
  }
}
class Main extends StatefulWidget {

  const Main({ Key? key }) : super(key: key);

  @override
  // ignore: library_private_types_in_public_api
  _MainState createState() => _MainState();
}

class _MainState extends State<Main> {

  @override
  Widget build(BuildContext context) {
    return const TabsPage();
  }
}

Flutter 返回上一级路由

Navigator.of(context).pop();

Flutter 中替换路由

比如我们从用户中心页面跳转到了registerFirst页面,然后从registerFirst页面通过 pushReplacementNamed跳转到了registerSecond页面。这个时候当我们点击registerSecond的返回 按钮的时候它会直接返回到用户中心。

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

Flutter 返回到根路由

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

Navigator.of(context).pushAndRemoveUntil(
  MaterialPageRoute(builder: (BuildContext context) {
  return const Tabs();
}), (route) => false);

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

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

routers.dart中引入cupertino.dart

import 'package:flutter/cupertino.dart';

MaterialPageRoute改为CupertinoPageRoute

import 'package:flutter/cupertino.dart';
import '../pages/tabs.dart';
import '../pages/shop.dart';
import '../pages/user/login.dart';
import '../pages/user/registerFirst.dart';
import '../pages/user/registerSecond.dart';
import '../pages/user/registerThird.dart';

//1、配置路由
Map routes = {
    "/": (contxt) => const Tabs(),
    "/login": (contxt) => const LoginPage(),
    "/registerFirst": (contxt) => const RegisterFirstPage(),
    "/registerSecond": (contxt) => const RegisterSecondPage(),
    "/registerThird": (contxt) => const RegisterThirdPage(),
    "/shop": (contxt, {arguments}) => ShopPage(arguments: arguments),
};
// 2、配置onGenerateRoute 固定写法 这个方法也相当于一个中间件,这里可以做权限判断

var onGenerateRoute = (RouteSettings settings) {
  final String? name = settings.name; // /news 或者 /search
  final Function? pageContentBuilder = routes[name]; //
  Function = (contxt) { return const NewsPage();};
  if (pageContentBuilder != null) {
    if (settings.arguments != null) {
      final Route route = CupertinoPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      final Route route =
      CupertinoPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
  return null;
};

全局配置主题

return MaterialApp(
  debugShowCheckedModeBanner: false,
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
    appBarTheme: const AppBarTheme(
    centerTitle: true,
  )
),
  initialRoute: "/",
  onGenerateRoute: onGenerateRoute,
);

results matching ""

    No results matching ""