0
点赞
收藏
分享

微信扫一扫

使用 GoRouter 进行 Flutter 导航:Go 与 Push


使用 GoRouter 进行 Flutter 导航:Go 与 Push

在使用 GoRouter 进行声明式路由时,深入解释 Go 和 Push 的区别

go_router 包是用于声明式路由的流行包。它基于 Navigator 2.0 API,目的是使用声明式路由来降低复杂性,无论您的目标平台是什么(移动、Web、桌面),处理来自 Android、iOS 和 Web 的深度和动态链接,以及其他一些导航相关的场景,同时(希望)提供易于使用的开发人员体验。所有这些都背后一个易于使用的 API。

如果您来自 Navigator 1.0,您将熟悉将路由送到导航堆栈的概念。

但是在使用 GoRouter 时,您有两个单独的选项:

  • go
  • push

本文将探讨两者的区别,以便您根据具体情况选择最合适的一种。

GoRouter 的声明式路由

首先,让我们考虑一个简单的路由层次结构,它由一个顶级路由和两个子路由组成:

GoRouter(
initialLocation: '/',
routes: [
// top-level route
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
routes: [
// one sub-route
GoRoute(
path: 'detail',
builder: (context, state) => const DetailScreen(),
),
// another sub-route
GoRoute(
path: 'modal',
pageBuilder: (context, state) => const MaterialPage(
fullscreenDialog: true,
child: ModalScreen(),
),
)
],
),
],
)

让我们为我们的路线定义 3 个页面:

使用 GoRouter 进行 Flutter 导航:Go 与 Push_前端主页、详细信息和model页面

从顶部路线导航

现在,假设我们在 ​​HomeScreen​​中,这只是一个带有三个按钮的简单页面,回调定义如下:

// onPressed callback for the first button
context.go('/detail'),
// onPressed callback for the second button
context.push('/detail'),
// onPressed callback for the third button
context.go('/modal'),

第一个和第二个回调具有相同的目标位置( ​​/detail​​),因此它们的行为方式相同。

也就是说,在这两种情况下,我们都会在导航堆栈中得到两条路线(home → detail)。

使用 GoRouter 进行 Flutter 导航:Go 与 Push_ide_02

Go 和 Push 的区别

从详细信息页面,我们现在可以通过​​/modal​​两种不同的方式导航到:

// onPressed callback for the first button
context.go('/modal'),
// onPressed callback for the second button
context.push('/modal'),

使用 GoRouter 进行 Flutter 导航:Go 与 Push_ide_03**

这一次的结果不同:

  • 如果我们使用​​go​​,我们最终会在主页顶部显示模页面
  • 如果我们使用​​push​​,我们最终会在详细信息页面的顶部出现模态页面

使用 GoRouter 进行 Flutter 导航:Go 与 Push_sed_04

go 通过丢弃之前的路由(/detail)跳转到目标路由(/modal),因为 /modal 不是 /detail 的子路由:

使用 GoRouter 进行 Flutter 导航:Go 与 Push_sed_05

具有 3 条路线的路线层次结构:请注意,modal 不是详细的子路线

同时,​​push​​总是将目标路由添加到现有路由之上,保留导航堆栈。

这意味着一旦我们关闭模态页面,我们将导航回:

  • 如果我们使用​​go​​,返回主页,
  • 如果我们使用​​push​​,返回详细信息页面

这是一个显示此行为的简短视频:

使用 GoRouter 进行 Flutter 导航:Go 与 Push_堆栈_06

最后附上完整源代码:

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

void main() {
WidgetsFlutterBinding.ensureInitialized();
GoRouter.setUrlPathStrategy(UrlPathStrategy.path);
runApp(const MyApp());
}

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

@override
Widget build(BuildContext context) {
final goRouter = GoRouter(
debugLogDiagnostics: true,
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
routes: [
GoRoute(
path: 'detail',
builder: (context, state) => const DetailScreen(),
),
GoRoute(
path: 'modal',
pageBuilder: (context, state) => const MaterialPage(
fullscreenDialog: true,
child: ModalScreen(),
),
)
],
),
],
);
return MaterialApp.router(
routerDelegate: goRouter.routerDelegate,
routeInformationParser: goRouter.routeInformationParser,
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.amber,
),
);
}
}

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

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home Page'),
backgroundColor: Colors.red,
),
backgroundColor: Colors.red,
body: Padding(
padding: const EdgeInsets.all(32.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () => context.go('/detail'),
child: const CenteredText('go /detail'),
),
const SizedBox(
height: 32,
),
ElevatedButton(
onPressed: () => context.push('/detail'),
child: const CenteredText('push /detail'),
),
const SizedBox(
height: 32,
),
ElevatedButton(
onPressed: () => context.go('/modal'),
child: const CenteredText('go /modal'),
),
],
),
),
),
);
}
}

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

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Detail Page'),
backgroundColor: Colors.green,
),
backgroundColor: Colors.green,
body: Padding(
padding: const EdgeInsets.all(32.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
ElevatedButton(
onPressed: () => context.go('/modal'),
child: const CenteredText('go /modal'),
),
const SizedBox(
height: 32,
),
ElevatedButton(
onPressed: () => context.push('/modal'),
child: const CenteredText('push /modal'),
),
],
),
),
),
);
}
}

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

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Modal Page'),
backgroundColor: Colors.blue,
),
backgroundColor: Colors.blue,
);
}
}

class CenteredText extends StatelessWidget {
const CenteredText(this.text, {Key? key}) : super(key: key);
final String text;
@override
Widget build(BuildContext context) {
return Text(
text,
style: const TextStyle(fontSize: 30),
textAlign: TextAlign.center,
);
}
}

结论

将 go 视为跳到新路线的一种方式。 如果新路由不是旧路由的子路由,这将修改底层导航堆栈。

另一方面,push 将始终将目标路由推送到现有导航堆栈的顶部。

有关 GoRouter 的更多信息,请务必查看官方文档。

举报

相关推荐

0 条评论