亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Flutter中g(shù)o_router路由管理的使用指南

 更新時(shí)間:2023年08月24日 08:21:06   作者:島上碼農(nóng)  
go_router?是一個(gè)?Flutter?的第三方路由插件,相比?Flutter?自帶的路由,go_router?更加靈活,而且簡(jiǎn)單易用,下面小編就來(lái)和大家聊聊go_router的使用吧

前言

go_router 是一個(gè) Flutter 的第三方路由插件,相比 Flutter 自帶的路由,go_router 更加靈活,而且簡(jiǎn)單易用。在 App 應(yīng)用中,如果你想自己控制路由的定義和管理方式,那么它將十分有用。同時(shí),對(duì)于 Web 應(yīng)用來(lái)說(shuō),go_router 也提供了很好的支持。 使用 go_router 后,你可以定義 URL 的格式,使用 URL 跳轉(zhuǎn),處理深度鏈接以及其他一系列的導(dǎo)航相關(guān)的應(yīng)用場(chǎng)景。

GoRouter 特性

GoRouter 針對(duì)頁(yè)面導(dǎo)航提供了下面這些特性:

  • 使用模板語(yǔ)法解析路由路徑和路由查詢(query)參數(shù);
  • 支持單個(gè)目標(biāo)路由展示多個(gè)頁(yè)面(子路由);
  • 重定向:可以基于應(yīng)用狀態(tài)跳轉(zhuǎn)到不同的URL,比如用戶沒(méi)有登錄時(shí)跳轉(zhuǎn)到登錄頁(yè);
  • 使用 StatefulShellRoute 可以支持嵌套的 Tab 導(dǎo)航;
  • 同時(shí)支持 Material 風(fēng)格和 Cupertino 風(fēng)格應(yīng)用;
  • 兼容 Navigator API 。

添加插件

當(dāng)前最新版本的 go_router 是10.0.0(6.3.0版本以上需要 Dart 2.18),可以根據(jù)自己的需要添加相應(yīng)的版本。在 pubspec.yaml 中加入依賴的版本即可,下面是以7.1.1版本為例。

dependencies:
  go_router: ^7.1.1

路由配置

引入 go_router 插件后,就可以在應(yīng)用中配置 GoRouter,代碼如下:

import 'package:go_router/go_router.dart';
// GoRouter configuration
final _router = GoRouter(
  initialLocation: '/',
  routes: [
    GoRoute(
      name: 'home', // Optional, add name to your routes. Allows you navigate by name instead of path
      path: '/',
      builder: (context, state) => HomeScreen(),
    ),
    GoRoute(
      name: 'page2',
      path: '/page2',
      builder: (context, state) => Page2Screen(),
    ),
  ],
);

然后,我們就可以通過(guò)MaterialApp.routerCupertinoApp.router構(gòu)造函數(shù)來(lái)使用 GoRouter,并且將 routerConfig 參數(shù)設(shè)置為我們前面定義的 GoRouter 配置對(duì)象。

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

接下來(lái)就可以愉快地玩耍 GoRouter 了。

路由參數(shù)

GoRouter 的每一個(gè)路由都通過(guò) GoRoute對(duì)象來(lái)配置,我們可以在構(gòu)建 GoRoute 對(duì)象時(shí)來(lái)配置路由參數(shù)。路由參數(shù)典型的就是路徑參數(shù),比如 /path/:{路徑參數(shù)},這個(gè)時(shí)候 GoRoute的路徑參數(shù)和很多 Web 框架的路由是一樣的,通過(guò)一個(gè)英文冒號(hào)加參數(shù)名稱就可以配置,之后我們可以在回調(diào)方法中通過(guò) GoRouterState 對(duì)象獲取路徑參數(shù),這個(gè)參數(shù)就可以傳遞到路由跳轉(zhuǎn)目的頁(yè)面。

GoRoute(
  path: '/fruits/:id',
  builder: (context, state) {
     final id = state.params['id'] // Get "id" param from URL
     return FruitsPage(id: id);
  },
),

同樣,也可以從GoRouterState中獲取 URL 路徑中的查詢(query)參數(shù),例如下面的代碼就是從/fruits?search=antonio中獲取search參數(shù)。

GoRoute(
  path: '/fruits',
  builder: (context, state) {
    final search = state.queryParams['search'];
    return FruitsPage(search: search);
  },
),

添加子路由

路由匹配后可以支持多個(gè)頁(yè)面(即子路由),當(dāng)一個(gè)新的頁(yè)面在舊的頁(yè)面之上展示時(shí),這個(gè)時(shí)候的效果和調(diào)用 push方法是一樣的,。如果頁(yè)面提供了 AppBar 組件的話,那么會(huì)自動(dòng)增加返回按鈕。 要使用子路由,我們只需要在上級(jí)路由中增加對(duì)應(yīng)的下級(jí)路由即可,代碼如下。

GoRoute(
  path: '/fruits',
  builder: (context, state) {
    return FruitsPage();
  },
  routes: <RouteBase>[ // Add child routes
    GoRoute(
      path: 'fruits-details', // NOTE: Don't need to specify "/" character for router's parents
      builder: (context, state) {
        return FruitDetailsPage();
      },
    ),
  ],
)

頁(yè)面導(dǎo)航

GoRouter 提供了多種方式跳轉(zhuǎn)到目的頁(yè)面,比如使用context.go()跳轉(zhuǎn)到指定的 URL 地址。

build(BuildContext context) {
  return TextButton(
    onPressed: () => context.go('/fruits/fruit-detail'),
  );
}

也可以使用路由的名稱進(jìn)行跳轉(zhuǎn),這個(gè)時(shí)候調(diào)用context.goNamed()即可。

build(BuildContext context) {
  return TextButton(
    // remember to add "name" to your routes
    onPressed: () => context.goNamed('fruit-detail'),
  );
}

如果要構(gòu)建查詢參數(shù),那么可以使用 Uri 類來(lái)構(gòu)建路由路徑。

context.go(
  Uri(
    path: '/fruit-detail',
    queryParameters: {'id': '10'},
   ).toString(),
);

如果要從當(dāng)前頁(yè)面返回的話,調(diào)用context.pop()即可。

嵌套導(dǎo)航

有些應(yīng)用在同一個(gè)頁(yè)面展示多個(gè)子頁(yè)面,例如 BottomNavigationBar 在進(jìn)行導(dǎo)航的時(shí)候就可以一直保留在屏幕底部。這種其實(shí)是嵌套導(dǎo)航,在 GoRouter 里,可以通過(guò)StatefulShellRoute來(lái)實(shí)現(xiàn)。 StatefulShellRoute不直接使用根導(dǎo)航(root Navigator),而是通過(guò)不同的導(dǎo)航的子路由來(lái)實(shí)現(xiàn)嵌套導(dǎo)航。對(duì)于每一個(gè)導(dǎo)航分支,都會(huì)創(chuàng)建各自獨(dú)立的導(dǎo)航,相當(dāng)于是一個(gè)并行導(dǎo)航樹,從而實(shí)現(xiàn)了有狀態(tài)的嵌套導(dǎo)航。 當(dāng)我們使用BottomNavigationBar的時(shí)候,就可以為很方便地為每一個(gè) Tab 配置一個(gè)持久的導(dǎo)航狀態(tài)。 StatefulShellRoute通過(guò)指定一個(gè)StatefulShellBranch類型的列表來(lái)完成,列表每一個(gè)元素代表路由樹的一個(gè)獨(dú)立的有狀態(tài)的分支。StatefulShellBranch為每個(gè)分支提供了根路由和 Navigator key(GlobalKey),并提供了可選的初始默認(rèn)路由地址。 我們來(lái)看看具體怎么實(shí)現(xiàn)。 首先創(chuàng)建我們的 GoRouter 對(duì)象,這個(gè)時(shí)候我們需要添加StatefulShellRoute.indexedStack到路由中,這個(gè)類負(fù)責(zé)創(chuàng)建嵌套路由。StatefulShellRoute.indexedStack() 實(shí)際上是使用了 IndexedStack創(chuàng)建了一個(gè)StatefulShellRoute。 這個(gè)構(gòu)造函數(shù)使用IndexedStack來(lái)管理每個(gè)分支導(dǎo)航的頁(yè)面,示例代碼如下:

// Create keys for `root` & `section` navigator avoiding unnecessary rebuilds
final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _sectionNavigatorKey = GlobalKey<NavigatorState>();
final router = GoRouter(
  navigatorKey: _rootNavigatorKey,
  initialLocation: '/feed',
  routes: <RouteBase>[
    StatefulShellRoute.indexedStack(
      builder: (context, state, navigationShell) {
        // Return the widget that implements the custom shell (e.g a BottomNavigationBar).
        // The [StatefulNavigationShell] is passed to be able to navigate to other branches in a stateful way.
        return ScaffoldWithNavbar(navigationShell);
      },
      branches: [
        // The route branch for the 1o Tab
        StatefulShellBranch(
          navigatorKey: _sectionNavigatorKey,
          // Add this branch routes
          // each routes with its sub routes if available e.g feed/uuid/details
          routes: <RouteBase>[
            GoRoute(
              path: '/feed',
              builder: (context, state) => const FeedPage(),
              routes: <RouteBase>[
                GoRoute(
                  path: 'detail',
                  builder: (context, state) => const FeedDetailsPage(),
                )
              ],
            ),
          ],
        ),
        // The route branch for 2o Tab
        StatefulShellBranch(routes: <RouteBase>[
          // Add this branch routes
          // each routes with its sub routes if available e.g shope/uuid/details
          GoRoute(
            path: '/shope',
            builder: (context, state) => const ShopePage(),
          ),
        ])
      ],
    ),
  ],
);

在上面的代碼中,我們?cè)诼酚芍屑尤肓?code>StatefulShellRoute.indexedStack(),由它負(fù)責(zé)創(chuàng)建路由分支以及返回一個(gè)自定義的導(dǎo)航殼,這里是BottomNavigationBar

  • 在 builder 參數(shù)中, 我們返回導(dǎo)航用的殼,一個(gè)簡(jiǎn)單的帶有BottomNavigationBarScaffold,這里需要記得將navigationShell傳給頁(yè)面,因?yàn)槲覀冃枰盟鼇?lái)導(dǎo)航到其他分支,例如從Home到 Shope。
  • 在路由分支數(shù)組branches中,我們提供了一個(gè)StatefulShellBranch 的數(shù)組。這里只需要給第一個(gè)元素的navigatorKey提供之前創(chuàng)建的全局的_sectionNavigatorKey。其他分支則使用默認(rèn)的 key。同時(shí),為每個(gè)分支提供了一個(gè)RouteBase列表,該列表是對(duì)應(yīng)分支的路由。

下面是我們定義的帶有BottomNavigationBar的自定義導(dǎo)航殼的代碼。

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class ScaffoldWithNavbar extends StatelessWidget {
  const ScaffoldWithNavbar(this.navigationShell, {super.key});
  /// The navigation shell and container for the branch Navigators.
  final StatefulNavigationShell navigationShell;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: navigationShell,
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: navigationShell.currentIndex,
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(icon: Icon(Icons.shop), label: 'Shope'),
        ],
        onTap: _onTap,
      ),
    );
  }
  void _onTap(index) {
    navigationShell.goBranch(
      index,
      // A common pattern when using bottom navigation bars is to support
      // navigating to the initial location when tapping the item that is
      // already active. This example demonstrates how to support this behavior,
      // using the initialLocation parameter of goBranch.
      initialLocation: index == navigationShell.currentIndex,
    );
  }
}

在上面的代碼中,實(shí)際上就是構(gòu)建帶有BottomNavigationBarScaffold然后 body 是從路由里獲取的navigationShell. 路由分支及頁(yè)面的切換通過(guò)_onTap(index) 實(shí)現(xiàn),當(dāng)點(diǎn)擊某個(gè) Tab 時(shí),就使用navigationShell.goBranch(index)來(lái)完成切換動(dòng)作。完整代碼:flutter-go_router-with-nested-tab-navigation

路由守衛(wèi)(Guards)

有些路由地址需要守衛(wèi),例如對(duì)于沒(méi)有登錄的用戶,有些頁(yè)面就無(wú)法訪問(wèn)。GoRouter 可以設(shè)置全局的重定向路由。最常見的一個(gè)場(chǎng)景就是對(duì)于沒(méi)有登錄的用戶,跳轉(zhuǎn)到/login 登錄頁(yè)面。 在 GoRouter 中,可以通過(guò)redirect 參數(shù)配置重定向,這是一個(gè)GoRouterRedirect的回調(diào)方法。如果要基于應(yīng)用狀態(tài)更改跳轉(zhuǎn)都只,那么既可以在GoRouterGoRoute的構(gòu)造方法中增加redirect參數(shù)。其中 GoRoute是只針對(duì)當(dāng)前路由進(jìn)行跳轉(zhuǎn)處理,而GoRouter這是全局處理。下面是示例代碼,如果不需要跳轉(zhuǎn),則在回調(diào)方法中返回 null即可。

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

也可以指定一個(gè)redirectLimit參數(shù)來(lái)限制最大的跳轉(zhuǎn)次數(shù),這個(gè)值默認(rèn)是5。如果超過(guò)了跳轉(zhuǎn)次數(shù),則會(huì)顯示一個(gè)錯(cuò)誤頁(yè)面。

轉(zhuǎn)場(chǎng)動(dòng)畫

GoRouter支持為每個(gè) GoRoute自定義轉(zhuǎn)場(chǎng)動(dòng)畫,這可以通過(guò)GoRoute的構(gòu)造函數(shù)的pageBuilder 參數(shù)來(lái)完成,下面是示例代碼。

GoRoute(
  path: '/fruit-details',
  pageBuilder: (context, state) {
    return CustomTransitionPage(
      key: state.pageKey,
      child: FruitDetailsScreen(),
      transitionsBuilder: (context, animation, secondaryAnimation, child) {
        // Change the opacity of the screen using a Curve based on the the animation's value
        return FadeTransition(
          opacity: CurveTween(curve: Curves.easeInOutCirc).animate(animation),
          child: child,
        );
      },
    );
  },
),

完整的示例代碼可以在 GitHub 查看:自定義轉(zhuǎn)場(chǎng)動(dòng)畫源碼。

錯(cuò)誤處理(404頁(yè)面)

go_routerMaterialAppCupertinoApp定義了默認(rèn)的錯(cuò)誤頁(yè)面,也可以通過(guò) errorBuilder 參數(shù)自定義錯(cuò)誤頁(yè)面,代碼如下。

GoRouter(
  /* ... */
  errorBuilder: (context, state) => ErrorPage(state.error),
);

類型安全路由

除了使用 URL 進(jìn)行路由導(dǎo)航外,go_router 也通過(guò)go_router_builder插件提供了類型安全路由,這可以通過(guò)代碼生成來(lái)完成。要使用這種方式,需要在pubspec.yaml增加下面這些依賴。

dev_dependencies:
  go_router_builder: ^1.0.16
  build_runner: ^2.3.3
  build_verify: ^3.1.0

定義路由

Then define each route as a class extending GoRouteData and overriding the build method.

class HomeRoute extends GoRouteData {
  const HomeRoute();
  @override
  Widget build(BuildContext context, GoRouterState state) => const HomeScreen();
}

路由樹

路由樹基于每個(gè)頂層的路由來(lái)定義,代碼如下。

import 'package:go_router/go_router.dart';
part 'go_router.g.dart'; // name of generated file
// Define how your route tree (path and sub-routes)
@TypedGoRoute<HomeScreenRoute>(
    path: '/home',
    routes: [ // Add sub-routes
      TypedGoRoute<SongRoute>(
        path: 'song/:id',
      )
    ]
)
// Create your route screen that extends "GoRouteData" and @override "build"
// method that return the screen for this route
@immutable
class HomeScreenRoute extends GoRouteData {
  @override
  Widget build(BuildContext context) {
    return const HomeScreen();
  }
}
@immutable
class SongRoute extends GoRouteData {
  final int id;
  const SongRoute({required this.id});
  @override
  Widget build(BuildContext context) {
    return SongScreen(songId: id.toString());
  }
}

之后可以運(yùn)行代碼生成來(lái)構(gòu)建類型安全路由。

flutter pub global activate build_runner // Optional, if you already have build_runner activated so you can skip this step
flutter pub run build_runner build

導(dǎo)航的時(shí)候,就不再需要使用 URL的方式了,可以構(gòu)建一個(gè)GoRouteData對(duì)象然后調(diào)用go()即可。

TextButton(
  onPressed: () {
    const SongRoute(id: 2).go(context);
  },
  child: const Text('Go to song 2'),
),

路由跳轉(zhuǎn)監(jiān)測(cè)

go_router還提供了一個(gè)非常有用的特性,那就是路由導(dǎo)航監(jiān)測(cè)NavigatorObserver??梢酝ㄟ^(guò)給GoRouter增加一個(gè)NavigatorObserver對(duì)象來(lái)監(jiān)聽路由行為,例如 push、pop 或路由替換(replace)。這可以通過(guò)自定義 NavigatorObserver 的子類完成。

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

之后,在GoRouterobservers 參數(shù)中增加自定義的MyNavigatorObserver 即可完成對(duì)所有觸發(fā)路由跳轉(zhuǎn)的行為的監(jiān)聽。

GoRouter(
  ...
  observers: [ // Add your navigator observers
    MyNavigatorObserver(),
  ],
...
)

完整的示例代碼見 GitHub: flutter-with-go_router: A simple app to show how to work with go_router。

到此這篇關(guān)于Flutter中g(shù)o_router路由管理的使用指南的文章就介紹到這了,更多相關(guān)Flutter go_router內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android水波紋載入控件CircleWaterWaveView使用詳解

    Android水波紋載入控件CircleWaterWaveView使用詳解

    這篇文章主要為大家詳細(xì)介紹了Android水波紋載入控件CircleWaterWaveView使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Android Studio設(shè)置繪制布局時(shí)的視圖

    Android Studio設(shè)置繪制布局時(shí)的視圖

    這篇文章介紹了Android Studio設(shè)置繪制布局時(shí)視圖的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • Android如何實(shí)現(xiàn)設(shè)備的異顯功能詳解

    Android如何實(shí)現(xiàn)設(shè)備的異顯功能詳解

    這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)設(shè)備的異顯功能的相關(guān)資料,這篇文章通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Android實(shí)現(xiàn)懸浮窗全系統(tǒng)版本

    Android實(shí)現(xiàn)懸浮窗全系統(tǒng)版本

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)懸浮窗全系統(tǒng)版本,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • Android LayerDrawable使用實(shí)例

    Android LayerDrawable使用實(shí)例

    這篇文章主要介紹了Android LayerDrawable使用實(shí)例,本文講解了LayerDrawable的作用、LayerDrawable的原理、LayerDrawableLayerDrawable的使用實(shí)例等,需要的朋友可以參考下
    2015-06-06
  • Android中毛玻璃效果的兩種實(shí)現(xiàn)代碼

    Android中毛玻璃效果的兩種實(shí)現(xiàn)代碼

    這篇文章主要介紹了Android中毛玻璃效果的兩種實(shí)現(xiàn)代碼,第一種是使用JAVA算法FastBlur實(shí)現(xiàn),第二種是使用Android自帶類RenderScript 實(shí)現(xiàn),本文通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友參考下吧
    2024-08-08
  • Android onMeasure與onDraw及自定義屬性使用示例

    Android onMeasure與onDraw及自定義屬性使用示例

    這篇文章主要介紹了Android onMeasure與onDraw及自定義屬性使用示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-02-02
  • Android WebView基礎(chǔ)應(yīng)用詳解

    Android WebView基礎(chǔ)應(yīng)用詳解

    這篇文章主要為大家介紹了Android中WebView這一控件的基礎(chǔ)應(yīng)用,例如:播放音樂(lè),播放視頻等,文中的示例代碼講解詳細(xì),對(duì)于我們了解WebView很有幫助,需要的同學(xué)可以學(xué)習(xí)一下
    2021-12-12
  • Android布局ConstraintLayout代碼修改約束及輔助功能

    Android布局ConstraintLayout代碼修改約束及輔助功能

    這篇文章主要為大家介紹了Android布局ConstraintLayout代碼修改約束及輔助功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Android 仿微信聊天時(shí)間格式化顯示功能

    Android 仿微信聊天時(shí)間格式化顯示功能

    這篇文章主要介紹了Android 仿微信聊天時(shí)間格式化顯示功能,本文中還給大家簡(jiǎn)單介紹了在同一年的顯示規(guī)則和不在同一年的顯示規(guī)則。需要的朋友可以參考下
    2017-02-02

最新評(píng)論