您现在的位置是:首页 >学无止境 >Flutter学习之旅 - 路由网站首页学无止境

Flutter学习之旅 - 路由

yasinawolaopo 2024-06-14 17:18:54
简介Flutter学习之旅 - 路由

Flutter路由介绍

flutter中的路由通俗就是页面跳转。在Flutter中通过Navigator(学过reactjs小程序的小伙伴应该很清楚)组件管理路由导航
Flutter给我们提供了俩种配置路由跳转的方式: 1.基本路由 2.命名路由

普通路由

//格式
Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {
  return const WidgetName();
}));
//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 Text("搜索页面"),
    );
  }
}
//home.dart
import 'package:flutter/material.dart';
import 'package:flutter_luyou_learn/pages/search.dart'; //引入SearchPage

...
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  
  void initState() {
    super.initState();
    _tabController = TabController(length: 5, vsync: this);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          backgroundColor: const Color.fromRGBO(255, 255, 255, 1),
          leading: const CircleAvatar(
            backgroundImage: NetworkImage(imageUrl(String)),
          ),
          title: ElevatedButton(
            onPressed: () {
            //主要(路由)
              Navigator.of(context)
                  .push(MaterialPageRoute(builder: (BuildContext context) {
                return const SearchPage();
              }));
            },
            child: const Text("搜索"),
          ),
          bottom: TabBar(
            controller: _tabController,
            indicatorColor: Colors.red,
            labelColor: Colors.red,
            unselectedLabelColor: Colors.black,
            tabs: const [
              Tab(child: Text("直播")),
              Tab(child: Text("推荐")),
              Tab(child: Text("热门")),
              Tab(child: Text("动画")),
              Tab(child: Text("影视")),
            ],
          )),
      body: TabBarView(
        controller: _tabController,
        children: const [
          Text("直播页"),
          Text("推荐页"),
          Text("热门页"),
          Text("动画页"),
          Text("影视页")
        ],
      ),
    );
  }
}

模板的知识请看这里

普通路由传值

跳转传值和调用组件传值的实现方法是一样的

//download.dart (新建一个组件)
import 'package:flutter/material.dart';

class DownloadPage extends StatefulWidget {
  final String titleMsg; //像传值一样定义
  const DownloadPage({
    super.key,
    this.titleMsg = "已经缓存视频", //没有传入默认使用这个
  });

  
  State<DownloadPage> createState() => _DownloadPageState();
}

class _DownloadPageState extends State<DownloadPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("离线缓存"),
      ),
      // body: const Text("你好"),
      body: _DownloadPageBody(
        titleMsg: widget.titleMsg, //获取DownloadPage里的属性titleMsg
      ),
    );
  }
}

class _DownloadPageBody extends StatelessWidget {
  String titleMsg;
  _DownloadPageBody({Key? key, required this.titleMsg}) : super(key: key);
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          width: 100,
          height: 50,
          decoration: const BoxDecoration(),
          child: Text(titleMsg),//显示输出
        )
      ],
    );
  }
}

//my.dart(关键代码)
ElevatedButton(
  onPressed: () {
    Navigator.of(context).push(MaterialPageRoute(
      builder: (BuildContext context) {
        return const DownloadPage(titleMsg: "测试",);
        //return const DownloadPage();
      }));
  },
  child: const Icon(Icons.ads_click),//随意
),

命名路由

//lib.main.dart
import 'package:flutter/material.dart';
import 'package:项目名/pages/tabs.dart';
import 'package:项目名/pages/tabs/my.dart';

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

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

  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      //记住这里不能写const MaterialApp()
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      // home: Tabs(),  //去除
      routes: {//添加
        '/': (context) => const Tabs(),
        '/search': (context) => const SearchPage()
      },
    );
  }
}
//lib/pages/tabs.dart
import 'package:flutter/material.dart';
//import 'package:项目名/lib目录下的文件或文件夹'
import 'package:项目名/pages/tabs/home.dart';
import 'package:项目名/pages/tabs/my.dart';

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

  
  State<Tabs> createState() => _TabsState();
}

class _TabsState extends State<Tabs> {
  int _currentIndex = 0;
  //添加
  final List<Widget> _pages = const [HomePage(), MyPage()];
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      body: _pages[_currentIndex], //修改
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          //index:点击索引值
          // print(index);
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(
              icon: Icon(Icons.my_library_add_outlined), label: "我的")
        ],
      ),
    );
  }
}

//home.dart(命名路由跳转关键代码)
ElevatedButton(
  onPressed: () {
    //格式:Navigator.pushNamed(context, '/跳转的路径名称');
    Navigator.pushNamed(context, '/search'); //命名路由跳转
  },
  child: const Text("搜索"),
),

routes的配置提到外面(使用的是Map)

  1. 配置主函数main.dart
//main.dart
import 'package:flutter/material.dart';
import 'package:mmly_learn_flutter/pages/tabs.dart';
import 'package:mmly_learn_flutter/pages/tabs/my.dart';
import 'package:mmly_learn_flutter/pages/tabs/search.dart';

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

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

  //1、配置路由
  Map<String, WidgetBuilder> routes = {
    '/': (context) => const Tabs(),
    '/search': (context) => const SearchPage()
  };
  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      //记住这里不能写const MaterialApp()
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      // home: Tabs(),
      initialRoute: "/", //初始化路由
      onGenerateRoute: (RouteSettings settings) {
        //2、配置路由(先把它当作固定格式)
        final String? name = settings.name;
        final Function? pageContrentBuilder = routes[name];
        if (pageContrentBuilder != null) {
          if (settings.name != null) {
            final Route route = MaterialPageRoute(
                builder: (context) => pageContrentBuilder(context,
                    arguments: settings.arguments));
            return route;
          }
          else {
            final Route route = MaterialPageRoute(
              builder: (context) => pageContrentBuilder!(context));
            return route;
          }
        } 
        return null;
      },
    );
  }
}

命名路由传值

跳转页面后传值

//search.dart(找到你需要跳转的页面进行处理)
import 'package:flutter/material.dart';

class SearchPage extends StatefulWidget {
  final Map arguments; //在需要传值的页面传入命名路由导航的argments
  const SearchPage({super.key, required this.arguments});

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

class _SearchPageState extends State<SearchPage> {
  
  void initState() {
    super.initState();
    print(widget.argments); //查看传入的值
    // print(widget.arguments['name']);//赋值格式
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("搜索"),
      ),
    );
  }
}
//main.dart(配置了routes的组件中,一般是main.dart)
Map<String, WidgetBuilder> routes = {
  '/': (context) => const Tabs(),
  '/search': (context, {argments}) => SearchPage(arguments: arguments)
};
//home.dart(点击跳转的按钮或者组件)
Navigator.pushNamed(context, '/search', arguments: {"title": "我是命名路由传值", "aid": 10}); 

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

  //1、配置路由
  Map<String, WidgetBuilder> routes = {
    '/': (context) => const Tabs(),
    '/search': (context, {arguments}) => SearchPage(arguments: arguments),
    '/login': (context) => const LoginPage(),
    '/loginFirst': (context) => const LoginFirstPage()
  };
  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      //记住这里不能写const MaterialApp()
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      // home: Tabs(),
      initialRoute: "/", //初始化路由
      onGenerateRoute: (RouteSettings settings) {
        //2、配置路由(先把它当作固定格式)
        final String? name = settings.name;
        final Function? pageContrentBuilder = routes[name];
        if (pageContrentBuilder != null) {
          if (settings.arguments != null) {
            final Route route = MaterialPageRoute(
                builder: (context) => pageContrentBuilder(context,
                    arguments: settings.arguments));
            return route;
          } else {
            final Route route = MaterialPageRoute(
                builder: (context) => pageContrentBuilder(context));
            return route;
          }
        }
        return null;
      },
    );
  }
}

上面写法后错误了

上图有可能(context, {argments}) => SearchPage(arguments: arguments)写成了(context, argments) => SearchPage(arguments: arguments)

  • settings: RouteSettings("/...",null)
  • settings.name: /...(路径名),
  • settings.arguments: null(传入的值)

路由跳转

我们希望跳转后接着跳转到另一个页面

  1. 首先实现1次跳转(步骤跟上面的知识一致,我们这里就以login为案例)
//lib/pages/user/login.dart
import 'package:flutter/material.dart';

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

  
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("登录页面"),
      ),
      body: Column(
        children: [ElevatedButton(onPressed: () {
        /*
        //返回上一级
        Navigator.of(context).pop();
        */}, child: const Text("执行登录"))],
      ),
    );
  }
}
//lib/main.dart(路由配置,不一定非是这个文件)
Map<String, WidgetBuilder> routes = {
    '/': (context) => const Tabs(),
    '/search': (context, {arguments}) => SearchPage(arguments: arguments),
    '/login': (context) => const LoginPage() //添加
  };
//lib/pages/tabs/home.dart(按自己喜好的文件)

返回上一级路由

//返回上一级
Navigator.of(context).pop();

替换路由

//当然替换的路由路径(/registerSecound)也要添加在Map routes配置中
//注意: 这个方法是将之前的页面进行替换(覆盖),所以之前的页面是销毁的
Navigator.of(context).pushReplacementNamed('/registerSecound')

返回到根路由

  1. 是使用Scaffold组件appBar
  2. 通过Navigator.of(context).pushAndRemoveUntil进行返回
Navigator.of(context).pushAndRemoveUntil(
  MaterialPageRoute(builder: (BuildContext context) {
    return const Tabs(); //返回到根页面
}), (route) => false);

返回Tabs后到指定页面

因为之前学习的时候有_currentIndex来指定底部在那个页面,所以

import 'package:flutter/material.dart';
//import 'package:项目名/lib目录下的文件或文件夹'
import 'package:mmly_learn_flutter/pages/tabs/home.dart';
import 'package:mmly_learn_flutter/pages/tabs/my.dart';

class Tabs extends StatefulWidget {
  final int index; //添加
  const Tabs({super.key, this.index = 0}); //添加

  
  State<Tabs> createState() => _TabsState();
}

class _TabsState extends State<Tabs> {
  int _currentIndex = 0;
  
  void initState() {
    //添加
    super.initState();
    _currentIndex = widget.index;
  } //修改

  //添加
  final List<Widget> _pages = const [HomePage(), MyPage()];
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: null,
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
          BottomNavigationBarItem(
              icon: Icon(Icons.my_library_add_outlined), label: "我的")
        ],
      ),
    );
  }
}

主要是添加(可以在上图代码中查看)

final int index;
this.index = 0
void initState() {...;_currentIndex = widget.index;}
Navigator.of(context).pushAndRemoveUntil(
                        MaterialPageRoute(builder: (BuildContext context) {
                      return const Tabs(index: 1); //注意: 这下标是以0开始的
                    }), (route) => false);
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。