Flutter路由构建辅助插件go_router_builder的使用

发布于 1周前 作者 songsunli 来自 Flutter

Flutter路由构建辅助插件 go_router_builder 的使用

go_router_builder 是一个用于简化和增强 go_router 插件的代码生成工具。它允许你定义强类型的路由,从而在编译时捕获错误,而不是在运行时。下面将详细介绍如何使用这个插件,并提供完整的示例。

依赖项

首先,在你的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  # 其他依赖...
  go_router: ^9.0.3

dev_dependencies:
  # 其他开发依赖...
  build_runner: ^2.0.0
  go_router_builder: ^2.3.0

源码结构

为了使用 go_router_builder,你需要导入 go_router.dart 库,并包含一个指向生成的 Dart 文件的 part 指令。生成的文件名总是 [source_file].g.dart

import 'package:go_router/go_router.dart';

part 'main.g.dart';

运行 build_runner

执行一次性的构建命令:

dart run build_runner build

更多信息可以参考 build_runner 的官方文档。

路由定义

每个路由都需要定义为继承自 GoRouteData 的类,并覆盖 build 方法。

class HomeRoute extends GoRouteData {
  const HomeRoute();

  @override
  Widget build(BuildContext context, GoRouterState state) => const HomeScreen();
}

路由树

路由树可以通过在顶级路由上定义属性来创建:

@TypedGoRoute<HomeRoute>(
  path: '/',
  routes: <TypedGoRoute<GoRouteData>>[
    TypedGoRoute<FamilyRoute>(
      path: 'family/:fid',
    ),
  ],
)
class HomeRoute extends GoRouteData {
  const HomeRoute();

  @override
  Widget build(BuildContext context, GoRouterState state) => const HomeScreen();
}

@TypedGoRoute<LoginRoute>(path: '/login')
class LoginRoute extends GoRouteData {
  LoginRoute({this.from});
  final String? from;

  @override
  Widget build(BuildContext context, GoRouterState state) {
    return LoginScreen(from: from);
  }
}

初始化 GoRouter

代码生成器会将所有顶级路由聚合到一个名为 $appRoutes 的列表中,以便初始化 GoRouter 实例:

final GoRouter router = GoRouter(routes: $appRoutes);

错误处理

你可以使用强类型路由来提供错误处理器:

class ErrorRoute extends GoRouteData {
  ErrorRoute({required this.error});
  final Exception error;

  @override
  Widget build(BuildContext context, GoRouterState state) {
    return ErrorScreen(error: error);
  }
}

final GoRouter routerWithErrorBuilder = GoRouter(
  routes: $appRoutes,
  errorBuilder: (BuildContext context, GoRouterState state) {
    return ErrorRoute(error: state.error!).build(context, state);
  },
);

导航

使用代码生成器提供的 gopush 方法进行导航:

void onTap() => const FamilyRoute(fid: 'f2').go(context);

返回值

go_router 6.5.0 开始,推送一个路由并在随后弹出它可以产生返回值。生成的路由也支持这一功能:

final bool? result = await const FamilyRoute(fid: 'John').push<bool>(context);

查询参数

未在路径中列出的参数表示查询参数:

@TypedGoRoute<LoginRoute>(path: '/login')
class LoginRoute extends GoRouteData {
  LoginRoute({this.from});
  final String? from;

  @override
  Widget build(BuildContext context, GoRouterState state) {
    return LoginScreen(from: from);
  }
}

默认值

对于非空类型的查询参数,可以定义默认值:

@TypedGoRoute<MyRoute>(path: '/my-route')
class MyRoute extends GoRouteData {
  MyRoute({this.queryParameter = 'defaultValue'});
  final String queryParameter;

  @override
  Widget build(BuildContext context, GoRouterState state) {
    return MyScreen(queryParameter: queryParameter);
  }
}

示例应用

下面是一个完整的示例应用,展示了如何使用 go_router_buildergo_router

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

import 'shared/data.dart';

part 'main.g.dart';

void main() => runApp(App());

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

  final LoginInfo loginInfo = LoginInfo();
  static const String title = 'GoRouter Example: Named Routes';

  @override
  Widget build(BuildContext context) => ChangeNotifierProvider<LoginInfo>.value(
        value: loginInfo,
        child: MaterialApp.router(
          routerConfig: _router,
          title: title,
          debugShowCheckedModeBanner: false,
        ),
      );

  late final GoRouter _router = GoRouter(
    debugLogDiagnostics: true,
    routes: $appRoutes,

    // 根据登录状态重定向
    redirect: (BuildContext context, GoRouterState state) {
      final bool loggedIn = loginInfo.loggedIn;
      final String loginLoc = const LoginRoute().location;
      final bool goingToLogin = state.matchedLocation == loginLoc;

      if (!loggedIn && !goingToLogin) {
        return LoginRoute(fromPage: state.matchedLocation).location;
      }

      if (loggedIn && goingToLogin) {
        return const HomeRoute().location;
      }

      return null;
    },

    refreshListenable: loginInfo,
  );
}

// 定义路由
@TypedGoRoute<HomeRoute>(
  path: '/',
  routes: <TypedGoRoute<GoRouteData>>[
    TypedGoRoute<FamilyRoute>(
      path: 'family/:fid',
      routes: <TypedGoRoute<GoRouteData>>[
        TypedGoRoute<PersonRoute>(
          path: 'person/:pid',
          routes: <TypedGoRoute<GoRouteData>>[
            TypedGoRoute<PersonDetailsRoute>(path: 'details/:details'),
          ],
        ),
      ],
    ),
    TypedGoRoute<FamilyCountRoute>(path: 'family-count/:count'),
  ],
)
class HomeRoute extends GoRouteData {
  const HomeRoute();

  @override
  Widget build(BuildContext context, GoRouterState state) => const HomeScreen();
}

@TypedGoRoute<LoginRoute>(
  path: '/login',
)
class LoginRoute extends GoRouteData {
  const LoginRoute({this.fromPage});

  final String? fromPage;

  @override
  Widget build(BuildContext context, GoRouterState state) =>
      LoginScreen(from: fromPage);
}

class FamilyRoute extends GoRouteData {
  const FamilyRoute(this.fid);

  final String fid;

  @override
  Widget build(BuildContext context, GoRouterState state) =>
      FamilyScreen(family: familyById(fid));
}

class PersonRoute extends GoRouteData {
  const PersonRoute(this.fid, this.pid);

  final String fid;
  final int pid;

  @override
  Widget build(BuildContext context, GoRouterState state) {
    final Family family = familyById(fid);
    final Person person = family.person(pid);
    return PersonScreen(family: family, person: person);
  }
}

class PersonDetailsRoute extends GoRouteData {
  const PersonDetailsRoute(this.fid, this.pid, this.details, {this.$extra});

  final String fid;
  final int pid;
  final PersonDetails details;
  final int? $extra;

  @override
  Page<void> buildPage(BuildContext context, GoRouterState state) {
    final Family family = familyById(fid);
    final Person person = family.person(pid);

    return MaterialPage<Object>(
      fullscreenDialog: true,
      key: state.pageKey,
      child: PersonDetailsPage(
        family: family,
        person: person,
        detailsKey: details,
        extra: $extra,
      ),
    );
  }
}

class FamilyCountRoute extends GoRouteData {
  const FamilyCountRoute(this.count);

  final int count;

  @override
  Widget build(BuildContext context, GoRouterState state) =>
      FamilyCountScreen(count: count);
}

通过上述步骤,你可以在 Flutter 应用中有效地使用 go_router_builder 来管理复杂的路由系统,并确保类型安全和更清晰的代码结构。


更多关于Flutter路由构建辅助插件go_router_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter路由构建辅助插件go_router_builder的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于go_router_builder这个Flutter路由构建辅助插件,我可以为你提供一个简单的代码示例来展示其使用方式。go_router_builder 是一个帮助开发者快速构建和管理 Flutter 应用中路由的辅助工具。请注意,实际使用时,你需要确保已经将该插件添加到你的 pubspec.yaml 文件中。

首先,确保你的 pubspec.yaml 文件中包含以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  go_router: ^x.y.z  # 替换为最新版本号
  go_router_builder: ^a.b.c  # 替换为最新版本号

然后运行 flutter pub get 来安装依赖。

以下是一个使用 go_router_builder 的简单示例:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationParser: _router.routeInformationParser,
      routerDelegate: _router.routerDelegate,
    );
  }

  late final GoRouter _router;

  @override
  void initState() {
    super.initState();
    _router = GoRouterBuilder()
      .addRoute(
        path: '/',
        name: 'home',
        builder: (context, state) => HomeScreen(),
      )
      .addRoute(
        path: '/details/:id',
        name: 'details',
        builder: (context, state) {
          final id = state.params['id']!;
          return DetailsScreen(id: id);
        },
      )
      .build();
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            // Navigate to details screen with an example ID
            context.goNamed('details', params: {'id': '123'});
          },
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

class DetailsScreen extends StatelessWidget {
  final String id;

  DetailsScreen({required this.id});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(
        child: Text('Details for ID: $id'),
      ),
    );
  }
}

在这个示例中,我们做了以下几件事:

  1. 依赖安装:确保在 pubspec.yaml 中添加了 go_routergo_router_builder 依赖。
  2. 初始化 GoRouter:在 MyAppinitState 方法中,使用 GoRouterBuilder 来构建路由。
  3. 定义路由:通过 .addRoute 方法定义了两个路由:一个是主页路由,另一个是带有参数的详情页路由。
  4. 导航:在 HomeScreen 中,使用 context.goNamed 方法导航到详情页,并传递一个参数。
  5. 显示详情:在 DetailsScreen 中,从路由参数中获取 ID 并显示。

这个示例展示了如何使用 go_router_builder 来简化路由的构建和管理过程。当然,根据实际需求,你可能需要添加更多的路由和复杂的逻辑。希望这个示例能帮到你!

回到顶部