flutter开发实战-go_router使用

flutter开发实战-go_router使用

在这里插入图片描述

一、go_router介绍与特性

go_router是一个Flutter的第三方声明式路由插件,使用路由器API提供一个方便的、基于url的API,用于在不同屏幕之间导航。可以定义URL模式、使用URL导航、处理深度链接以及许多其他与导航相关的场景。

GoRouter具有许多功能,使导航变得简单明了:

  • 使用模板语法解析路由路径和路由查询(query)参数;
  • 支持单个目标路由展示多个页面(子路由);
  • 重定向:可以基于应用状态跳转到不同的URL,比如用户没有登录时跳转到登录页;
  • 使用 StatefulShellRoute 可以支持嵌套的 Tab 导航;
  • 同时支持 Material 风格和 Cupertino 风格应用;
  • 兼容 Navigator API 。

二、引入go_router

根据自己需要的版本引入对应的版本,在pubspec.yaml加入

  go_router: ^8.2.0
    

稍后执行flutter pub get命令

三、go_router路由配置

引入插件后,我们需要配置MaterialApp.router的routerConfig

/// The route configuration.
final GoRouter _router = GoRouter(
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'details',
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
        ),
      ],
    ),
  ],
);
    

配置MaterialApp.router

/// The main app.
class MyApp extends StatelessWidget {
  /// Constructs a [MyApp]
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}
    

四、go_router路由跳转

如果跳转页面,可以使用content.go

context.go('/details')

4.1、路径参数

GoRouter 的每一个路由都通过 GoRoute对象来配置,可以通过路径参数进行传递相关参数到目标页面。例如路径comment/参数id

GoRoute(
          path: 'comment/:id',
          builder: (BuildContext context, GoRouterState state) {
            String? id = state.pathParameters['id'];
            print("id:${id}");// Get "id" param from URL
            return CommentScreen(id: id);
          },
        ),

那么可以通过context.go(’/comment/55555’)传参数

ElevatedButton(
          onPressed: () => context.go('/comment/55555'),
          child: const Text('Go to the comment screen'),
        )

4.2、路径查询参数

可以获取路径的查询参数 URL 路径中的查询(query)参数,例如从/search?keyword=myname中获取search参数。

GoRoute(
          path: 'search',
          builder: (BuildContext context, GoRouterState state) {
            String? keyword = state.queryParameters['keyword'];
            print("keyword:${keyword}"); // Get "id" param from URL
            return SearchScreen(keyword: keyword);
          },
        ),

传递参数context.go(’/search?keyword=myName’)目标页面可以得到参数myName

ElevatedButton(
              onPressed: () => context.go('/search?keyword=myName'),
              child: const Text('Go to the Search screen'),
            ),

五、添加子路由

子路由,路由匹配支持多个页面,当一个新的页面在旧的页面之上展示时

GoRoute(
          path: 'details',
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
          routes: <RouteBase>[
            // Add child routes
            GoRoute(
              path: 'sub-details',
              // NOTE: Don't need to specify "/" character for router’s parents
              builder: (context, state) {
                return SubDetailsScreen();
              },
            ),
          ],
        ),

可以通过context.go(’/details/sub-details’)来进行调用

ElevatedButton(
              onPressed: () => context.go('/details/sub-details'),
              child: const Text('Go to the SubDetails screen'),
            ),

六、页面导航

go_router提供多种方式进行跳转

context.goNamed方式

ElevatedButton(
              onPressed: () => context.goNamed('/details'),
              child: const Text('Go to the Details screen'),
            ),

七、路由重定向

go_router提供全局重定向,比如在没有登录的用户,需要跳转到登录页面.在 GoRouter 中,可以通过redirect 参数配置重定向.

redirect: (BuildContext context, GoRouterState state) {
    final isLogin = false;// your logic to check if user is authenticated
    if (!isLogin) {
      return '/login';
    } else {
      return null; // return "null" to display the intended route without redirecting
    }
  }

八、错误处理(404页面)

go_router为MaterialApp 和CupertinoApp定义了默认的错误页面,也可以通过 errorBuilder 参数自定义错误页面。

errorBuilder: (
    BuildContext context,
    GoRouterState state,
  ) {
    // ErrorPage
    return ErrorScreen();
  }

九、路由跳转监测

在flutter自带的会有NavigatorObserver,go_router页提供路由跳转监测功能

class MyNavigatorObserver extends NavigatorObserver {
  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print('did push route');
  }

  @override
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print('did pop route');
  }
}

在observers中配置

GoRouter(
  observers: [MyNavigatorObserver()],
...
)

这里只是代码尝试了一下常用功能。还有一些转场动画、嵌套导航等等特性需要去尝试。
可以查看https://juejin.cn/post/7270343009790853172

注意:不同版本的代码有所不同。

测试的完整代码如下

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

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

class MyNavigatorObserver extends NavigatorObserver {
  @override
  void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print('did push route');
  }

  @override
  void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
    print('did pop route');
  }
}

/// The route configuration.
final GoRouter _router = GoRouter(
  observers: [MyNavigatorObserver()],
  redirect: (BuildContext context, GoRouterState state) {
    final isLogin = false; // your logic to check if user is authenticated
    if (!isLogin) {
      return '/login';
    } else {
      return null; // return "null" to display the intended route without redirecting
    }
  },
  errorBuilder: (
    BuildContext context,
    GoRouterState state,
  ) {
    // ErrorPage
    return ErrorScreen();
  },
  routes: <RouteBase>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) {
        return const HomeScreen();
      },
      routes: <RouteBase>[
        GoRoute(
          path: 'details',
          builder: (BuildContext context, GoRouterState state) {
            return const DetailsScreen();
          },
          routes: <RouteBase>[
            // Add child routes
            GoRoute(
              path: 'sub-details',
              // NOTE: Don't need to specify "/" character for router’s parents
              builder: (context, state) {
                return SubDetailsScreen();
              },
            ),
          ],
        ),
        GoRoute(
          path: 'comment/:id',
          builder: (BuildContext context, GoRouterState state) {
            String? id = state.pathParameters['id'];
            print("id:${id}"); // Get "id" param from URL
            return CommentScreen(id: id);
          },
        ),
        GoRoute(
          path: 'search',
          builder: (BuildContext context, GoRouterState state) {
            String? keyword = state.queryParameters['keyword'];
            print("keyword:${keyword}"); // Get "id" param from URL
            return SearchScreen(keyword: keyword);
          },
        ),
      ],
    ),
  ],
);

/// The main app.
class MyApp extends StatelessWidget {
  /// Constructs a [MyApp]
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

/// The home screen
class HomeScreen extends StatelessWidget {
  /// Constructs a [HomeScreen]
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home Screen')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () => context.goNamed('/details'),
              child: const Text('Go to the Details screen'),
            ),
            SizedBox(
              height: 30,
            ),
            ElevatedButton(
              onPressed: () => context.go('/details/sub-details'),
              child: const Text('Go to the SubDetails screen'),
            ),
          ],
        ),
      ),
    );
  }
}

/// The details screen
class DetailsScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const DetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Details Screen')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () => context.go('/comment/55555'),
              child: const Text('Go to the comment screen'),
            ),
            SizedBox(
              height: 30,
            ),
            ElevatedButton(
              onPressed: () => context.go('/search?keyword=myName'),
              child: const Text('Go to the Search screen'),
            ),
          ],
        ),
      ),
    );
  }
}

/// The details screen
class SubDetailsScreen extends StatelessWidget {
  /// Constructs a [SubDetailsScreen]
  const SubDetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SubDetailsScreen Screen')),
      body: Center(
        child: ElevatedButton(
          onPressed: () => context.go('/details'),
          child: const Text('Go back to the Details screen'),
        ),
      ),
    );
  }
}

/// The details screen
class CommentScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const CommentScreen({super.key, this.id});

  final String? id;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('CommentScreen Screen')),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text("param id:${id}"),
          SizedBox(
            height: 30,
          ),
          ElevatedButton(
            onPressed: () => context.go('/'),
            child: const Text('Go back to the Details screen'),
          ),
        ],
      )),
    );
  }
}

/// The Search screen
class SearchScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const SearchScreen({super.key, this.keyword});

  final String? keyword;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('SearchScreen Screen')),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text("param keyword:${keyword}"),
          SizedBox(
            height: 30,
          ),
          ElevatedButton(
            onPressed: () => context.go('/'),
            child: const Text('Go back to the details screen'),
          ),
        ],
      )),
    );
  }
}

/// The Search screen
class ErrorScreen extends StatelessWidget {
  /// Constructs a [DetailsScreen]
  const ErrorScreen();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ErrorScreen Screen')),
      body: Center(
        child: Container(
          child: const Text('Error info'),
        ),
      ),
    );
  }
}

十、小结

flutter开发实战-go_router使用

学习记录,每天不停进步。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Flutter 的 go_router 进行进阶使用时,您可以探索以下功能和技巧: 1. 命名路由:除了使用路径来导航页面,go_router 还支持命名路由,通过给每个路由规则指定一个唯一的名称,可以更方便地进行页面跳转。例如: ```dart final routes = [ GoRoute( path: '/', pageBuilder: (context, state) => HomePage(), name: 'home', ), GoRoute( path: '/details/:id', pageBuilder: (context, state) => DetailsPage(id: state.params['id']), name: 'details', ), ]; ``` 然后,您可以通过名称进行页面跳转: ```dart GoRouter.of(context).goNamed('details', params: {'id': '123'}); ``` 2. 参数传递:go_router 允许您在页面之间传递参数。在路由规则中,可以定义参数占位符,然后在页面构建器中获取这些参数并使用它们。例如: ```dart final routes = [ GoRoute( path: '/details/:id', pageBuilder: (context, state) => DetailsPage(id: state.params['id']), ), ]; ``` 在 DetailsPage 中可以通过 `widget.id` 访问传递的参数。 3. 路由拦截和重定向:go_router 允许您在路由跳转之前进行拦截和处理。您可以使用 `beforeEnter` 方法来拦截特定的路由,并根据需要执行操作,例如权限验证、参数校验等。还可以使用 `redirectTo` 方法来重定向到其他路由。例如: ```dart final routes = [ GoRoute( path: '/details/:id', pageBuilder: (context, state) => DetailsPage(id: state.params['id']), beforeEnter: (context, state) { // 进行权限验证或其他操作 if (!isLoggedIn) { return redirectTo('/login'); } return null; }, ), ]; ``` 4. 页面切换动画:go_router 支持自定义页面切换动画,您可以为每个路由规则定义不同的动画效果。使用 `transitionDuration` 和 `transitionBuilder` 属性来自定义页面切换动画。例如: ```dart final routes = [ GoRoute( path: '/', pageBuilder: (context, state) => HomePage(), transitionDuration: Duration(milliseconds: 500), transitionBuilder: (context, animation, secondaryAnimation, child) { return FadeTransition(opacity: animation, child: child); }, ), ]; ``` 在上述示例中,我们使用了一个渐变的动画效果。 这些是 go_router 的一些进阶使用方法,您可以根据您的实际需求来灵活使用它们。请参考 go_router 的官方文档以获取更多详细信息和示例代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值