Flutter路由与导航

前言

页面跳转:
1、Android初始化 Intent通过 startActivity打开新页面
2、iOS初始化ViewController通过pushViewController 打开新页面
3、Rect navigation管理页面
Flutter 则借鉴上面两种类型

Flutter路由导航

在 Flutter 中,页面之间的跳转是通过 Route 和 Navigator 来管理的:
Route 是页面的抽象,主要负责创建对应的界面,接收参数,响应 Navigator 打开和关闭;
而 Navigator 则会维护一个路由栈管理 Route,Route 打开即入栈,Route 关闭即出栈,还可以直接替换栈内的某一个 Route。
而根据是否需要提前注册页面标识符,Flutter 中的路由管理可以分为两种方式:
1、基本路由。无需提前注册,在页面切换时需要自己构造页面实例。
2、命名路由。需要提前注册页面标识符,在页面切换时通过标识符直接打开新的路由。

基本路由:就是最原始的跳转方式

在 Flutter 中,基本路由的使用方法和 Android/iOS 打开新页面的方式非常相似
要导航到一个新的页面,我们需要创建一个MaterialPageRoute的实例,调用 Navigator.push 方法将新页面压到堆栈的顶部。其中,MaterialPageRoute 是一种路由模板,定义了路由创建及切换过渡动画的相关配置,可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。而如果我们想返回上一个页面,则需要调用 Navigator.pop 方法从堆栈中删除这个页面。

RaisedButton(
              child: Text('基本路由'),
              onPressed: () => Navigator.push(context,
                  MaterialPageRoute(builder: (context) => SecondPage()))),
 RaisedButton(
              child: Text('back'),
              onPressed: ()=> Navigator.pop(context,"Hi")
命名路由

每次跳转需要手动创建MaterialPageRoute 实例,初始化,然后push。
命名路由通过给页面起一个名字,通过页面名字打开即可。
要想通过名字来指定页面切换,我们必须先给应用程序 MaterialApp 提供一个页面名称映射规则,即路由表routes,这样 Flutter 才知道名字与页面 Widget 的对应关系。路由表实际上是一个Map,其中key 值对应页面名字,而 value 值则是一个 WidgetBuilder 回调函数,我们需要在这个函数中创建对应的页面。
而一旦在路由表中定义好了页面名字,我们就可以使用 Navigator.pushNamed 来打开页面了。
在注册路由表时,Flutter 提供了 UnknownRoute 属性,我们可以对未知的路由标识符进行统一的页面跳转处理。

/// 路由管理工具类
class RouterManager {
  /// 路由映射表 - 页面名称与页面构建器的对应关系
  static final Map<String, WidgetBuilder> _routes = {
    // 首页
    '/router': (context) => RouterTestPage(),
    '/second_page':(context)=>SecondPage(),
    '/third_page':(context)=>ThirdPage()
    // // 示例页面1
    // '/example1': (context) => const ExamplePage1(),
    // // 示例页面2(带参数)
    // '/example2': (context) => const ExamplePage2(),
    // 可以继续添加更多页面...
  };

  /// 路由观察者 - 用于监听路由变化
  static final RouteObserver<ModalRoute> routeObserver = RouteObserver<ModalRoute>();

  /// 生成路由
  static Route<dynamic> generateRoute(RouteSettings settings) {
    final String? name = settings.name;
    final Function? pageBuilder = _routes[name];

    // 路由拦截逻辑 - 可在此处添加登录验证等全局拦截
    /*
    if (_needLoginIntercept(name)) {
      // 如果需要登录但未登录,跳转到登录页
      return MaterialPageRoute(
        builder: (context) => const LoginPage(),
        settings: const RouteSettings(name: '/login'),
      );
    }

     */

    if (pageBuilder != null) {
      // 修正:只传递 context,不传递额外参数
      return MaterialPageRoute(
        builder: (context) => pageBuilder(context), // 仅传 context
        settings: settings, // 保留 settings 以存储参数
      );
    }
    // 未找到对应路由时返回404页面
    return MaterialPageRoute(
      builder: (context) => NotFoundPage(routeName: name),
    );
  }

跳转:
RouterManager.push(context, '/second_page'))

demo中罗列了 基础路由 命名路由传参的情形

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

class RouterTestPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _routerPageState();
}

class _routerPageState extends State<RouterTestPage> {
  String? _msg;
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('First Screen'),
      ),
      body: Column(
        children: <Widget>[
          RaisedButton(
              child: Text('基本路由'),
              onPressed: () => Navigator.push(context,
                  MaterialPageRoute(builder: (context) => SecondPage()))),
          RaisedButton(
              child: Text('命名路由'),
              // onPressed: ()=> Navigator.pushNamed(context,"/second_page")
              onPressed: () => RouterManager.push(context, '/second_page')),
          RaisedButton(
            child: Text('命名路由(参数&回调)'),
            onPressed: () => RouterManager.push(
              context,
              '/third_page',
              arguments: "Hey",
            ).then((msg) {
              setState(() {
                _msg = (msg ?? "啦啦啦") as String?;
              });
            }),
          ),
          //
          //   onPressed: ()=> Navigator.pushNamed(context, "/third_page",arguments: "Hey").then((msg) {
          //     setState(() {
          //       _msg = (msg ?? "啦啦啦") as String?;
          //     });
          //   }),
          // ),
          Text('Message from Second screen: $_msg'),
          RaisedButton(
              child: Text('命名路由异常处理'),
              onPressed: () => Navigator.pushNamed(context, "unknown_page"))
        ],
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Second Screen'),
      ),
      body: RaisedButton(
          child: Text('Back to first screen'),
          onPressed: () => RouterManager.pop(context),
    ));
  }
}

class ThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // String msg = ModalRoute.of(context)!.settings.arguments as String;
    // final Map? args = RouterManager.getArguments<Map>(context);
    final String? args = RouterManager.getArguments<String>(context);
    return Scaffold(
      appBar: AppBar(
        title: Text('Third Screen'),
      ),
      body: Column(
        children: <Widget>[
          Text('Message from first screen: ${args ?? "无参数"}'),
          // Text('Message from first screen: $msg'),
          RaisedButton(
              child: Text('back'),
              onPressed: () => RouterManager.pop(context,result: '我返回啦'))
              //onPressed: ()=> Navigator.pop(context,"Hi")
        ],
      ),
    );
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容