Flutter之命名路由管理

所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理。

Mobile apps typically reveal their contents via full-screen elements called "screens" or "pages". In Flutter these elements are called routes and they're managed by a Navigator widget. The navigator manages a stack of Route objects and provides two ways for managing the stack, the declarative API Navigator.pages or imperative API Navigator.push and Navigator.pop.

移动应用程序通常通过称为“屏幕”或“页面”的全屏元素显示其内容。 在 Flutter 中,这些元素称为路由,它们由导航器小部件管理。 导航器管理 Route 对象的堆栈,并提供两种管理堆栈的方法:声明式 API Navigator.pages 或命令式 API Navigator.push 和 Navigator.pop。

When your user interface fits this paradigm of a stack, where the user should be able to navigate back to an earlier element in the stack, the use of routes and the Navigator is appropriate. On certain platforms, such as Android, the system UI will provide a back button (outside the bounds of your application) that will allow the user to navigate back to earlier routes in your application's stack. On platforms that don't have this build-in navigation mechanism, the use of an AppBar (typically used in the Scaffold.appBar property) can automatically add a back button for user navigation.

当您的用户界面适合这种堆栈范例时,用户应该能够导航回堆栈中较早的元素,那么使用路由和导航器是合适的。

在某些平台(例如 Android)上,系统 UI 将提供后退按钮(在应用程序范围之外),允许用户导航回应用程序堆栈中较早的路由。 在没有这种内置导航机制的平台上,使用 AppBar(通常在 Scaffold.appBar 属性中使用)可以自动添加用于用户导航的后退按钮。

Although you can create a navigator directly, it's most common to use the navigator created by the Router which itself is created and configured by a WidgetsApp or a MaterialApp widget. You can refer to that navigator with Navigator.of.

MaterialApp is the simplest way to set things up. The MaterialApp's home becomes the route at the bottom of the Navigator's stack. It is what you see when the app is launched.

尽管您可以直接创建导航器,但最常见的是使用由 Router 创建的导航器,该导航器本身是由 WidgetsApp 或 MaterialApp 小部件创建和配置的。 您可以使用 Navigator.of 引用该导航器。

MaterialApp 是最简单的设置方法。 MaterialApp 的主页成为导航器堆栈底部的路线。 这是您在启动应用程序时看到的内容。

void main() {
  runApp(const MaterialApp(home: MyAppHome()));
}

To push a new route on the stack you can create an instance of MaterialPageRoute with a builder function that creates whatever you want to appear on the screen. For example:
要将新路由推送到堆栈上,您可以使用构建器函数创建一个 MaterialPageRoute 实例,该构建器函数可以创建您想要在屏幕上显示的任何内容。 例如:

Navigator.push(context, MaterialPageRoute<void>(
  builder: (BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('My Page')),
      body: Center(
        child: TextButton(
          child: const Text('POP'),
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
    );
  },
));

The route defines its widget with a builder function instead of a child widget because it will be built and rebuilt in different contexts depending on when it's pushed and popped.

As you can see, the new route can be popped, revealing the app's home page, with the Navigator's pop method:

该路由使用构建器函数而不是子窗口小部件定义其窗口小部件,因为它将根据推送和弹出的时间在不同的上下文中构建和重建。

如您所见,可以使用 Navigator 的 pop 方法弹出新路线,显示应用程序的主页:

Navigator.pop(context);

It usually isn't necessary to provide a widget that pops the Navigator in a route with a Scaffold because the Scaffold automatically adds a 'back' button to its AppBar. Pressing the back button causes Navigator.pop to be called. On Android, pressing the system back button does the same thing. 
通常不需要提供一个使用脚手架在路径中弹出导航器的小部件,因为脚手架会自动向其 AppBar 添加“后退”按钮。 按后退按钮会调用 Navigator.pop。 在 Android 上,按系统后退按钮会执行相同的操作。

Navigator

  • Future push(BuildContext context, Route route)

将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。

  • bool pop(BuildContext context, [ result ])

将栈顶路由出栈,result 为页面关闭时返回给上一个页面的数据。

  • 实例方法

Navigator类中第一个参数为context的静态方法都对应一个Navigator的实例方法, 比如

Navigator.push(BuildContext context, Route route)=Navigator.of(context).push(Route route)

普通路由

MaterialPageRoute 

MaterialPageRoute({
    WidgetBuilder builder,
    RouteSettings settings,
    bool maintainState = true,
    bool fullscreenDialog = false,
  })
  • builder 是一个WidgetBuilder类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个widget。我们通常要实现此回调,返回新路由的实例。
  • settings 包含路由的配置信息,如路由名称、是否初始路由(首页)。
  • maintainState:默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState为 false
  • fullscreenDialog表示新的路由页面是否是一个全屏的模态对话框,在 iOS 中,如果fullscreenDialogtrue,新页面将会从屏幕底部滑入(而不是水平方向)。

命名路由

  • 路由表(routing table)

要想使用命名路由,我们必须先提供并注册一个路由表(routing table),这样应用程序才知道哪个名字与哪个路由组件相对应。其实注册路由表就是给路由起名字,路由表的定义如下:

Map<String, WidgetBuilder> routes;
  • 注册路由表

MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  //注册路由表
  routes:{
   "new_page":(context) => NewRoute(),
    ... // 省略其他路由注册信息
  } ,
  home: MyHomePage(title: 'Flutter Demo Home Page'),
);
  • 通过路由名打开新路由页 

要通过路由名称来打开新路由,可以使用Navigator 的pushNamed方法:

Future pushNamed(BuildContext context, String routeName,{Object arguments})
  •  命名路由参数传递 

我们先注册一个路由:

 routes:{
   "new_page":(context) => EchoRoute(),
  } ,

 在打开路由时传递参数

Navigator.of(context).pushNamed("new_page", arguments: "hi");

在路由页通过RouteSetting对象获取路由参数:

class EchoRoute extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    //获取路由参数  
    var args=ModalRoute.of(context).settings.arguments;
    //...省略无关代码
  }
}
  • 路由生成钩子

路由生成钩子只会对命名路由生效

MaterialApp有一个onGenerateRoute属性,它在打开命名路由时可能会被调用,

当调用Navigator.pushNamed(...)打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的builder函数来生成路由组件;

如果路由表中没有注册,才会调用onGenerateRoute来生成路由。onGenerateRoute回调签名如下:

Route<dynamic> Function(RouteSettings settings)

在使用路由钩子时,您需要将要传递的参数放在RouteSettings对象中,并将该对象作为参数传递给Navigator.push方法。因此,您需要使用RouteSettings对象来传递数据。

  • 路由钩子参数传递

//路由封装
class Routers{
  
  static RouteFactory onGenerateRoute=(setting){
    if(setting.name=='/'){
      return MaterialPageRoute(builder: (context){return MainPage();});
    }
    if(setting.name=='/one'){
      return MaterialPageRoute(builder: (context){return Page_one(get_router: setting.arguments,);});
    }
  };
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class Page_one extends StatelessWidget {
  var get_router;

  Page_one({this.get_router});

  @override
  Widget build(BuildContext context) {
    //命名路由参数传递
    var get_data = ModalRoute.of(context)?.settings.arguments;
    return Scaffold(
      appBar: AppBar(
        title: Text("page_one"),
      ),
      body: Container(
        child: Column(
          children: [
            Text("红色页面"),
            ElevatedButton(
                onPressed: () {
                  print("page_one 返回主页");
                  Navigator.pop(context, "这里是从page_one返回主页的数据");
                },
                child: Text("返回主页")),
            Text("从主页接收的数据:${get_data}"),
            Text("使用路由钩子从主页接收的数据:${get_router}"),
          ],
        ),
      ),
    );
  }
}

onUnknownRoute

当我们打开的路由名称,根本不存在时使用onUnknownRoute可以跳转到一个统一的错误页面

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "7 路由管理",
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      onGenerateRoute:Routers.onGenerateRoute,
      /*当我们打开的路由名称,根本不存在时使用onUnknownRoute可以跳转到一个统一的错误页面*/
      onUnknownRoute: Routers.unknowRoute,
    );
  }
}
 //跳转错误显示页面
  static final RouteFactory unknowRoute=(settings){
    return MaterialPageRoute(builder: (context){
      return HYErroPage();
    });
  };
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

//跳转错误显示页面
class HYErroPage extends StatelessWidget {
  const HYErroPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("错误页面"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("ERRO!!!ERRO!!!",style: TextStyle(fontSize: 30,color: Colors.red),)
          ],
        ),
      ),
    );
  }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值