柚子快報邀請碼778899分享:flutter開發(fā)實戰(zhàn)-go
柚子快報邀請碼778899分享:flutter開發(fā)實戰(zhàn)-go
flutter開發(fā)實戰(zhàn)-go_router使用
一、go_router介紹與特性
go_router是一個Flutter的第三方聲明式路由插件,使用路由器API提供一個方便的、基于url的API,用于在不同屏幕之間導(dǎo)航。可以定義URL模式、使用URL導(dǎo)航、處理深度鏈接以及許多其他與導(dǎo)航相關(guān)的場景。
GoRouter具有許多功能,使導(dǎo)航變得簡單明了:
使用模板語法解析路由路徑和路由查詢(query)參數(shù);支持單個目標(biāo)路由展示多個頁面(子路由);重定向:可以基于應(yīng)用狀態(tài)跳轉(zhuǎn)到不同的URL,比如用戶沒有登錄時跳轉(zhuǎn)到登錄頁;使用 StatefulShellRoute 可以支持嵌套的 Tab 導(dǎo)航;同時支持 Material 風(fēng)格和 Cupertino 風(fēng)格應(yīng)用;兼容 Navigator API 。
二、引入go_router
根據(jù)自己需要的版本引入對應(yīng)的版本,在pubspec.yaml加入
go_router: ^8.2.0
稍后執(zhí)行flutter pub get命令
三、go_router路由配置
引入插件后,我們需要配置MaterialApp.router的routerConfig
/// The route configuration.
final GoRouter _router = GoRouter(
routes:
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) {
return const HomeScreen();
},
routes:
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路由跳轉(zhuǎn)
如果跳轉(zhuǎn)頁面,可以使用content.go
context.go('/details')
4.1、路徑參數(shù)
GoRouter 的每一個路由都通過 GoRoute對象來配置,可以通過路徑參數(shù)進(jìn)行傳遞相關(guān)參數(shù)到目標(biāo)頁面。例如路徑comment/參數(shù)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’)傳參數(shù)
ElevatedButton(
onPressed: () => context.go('/comment/55555'),
child: const Text('Go to the comment screen'),
)
4.2、路徑查詢參數(shù)
可以獲取路徑的查詢參數(shù) URL 路徑中的查詢(query)參數(shù),例如從/search?keyword=myname中獲取search參數(shù)。
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);
},
),
傳遞參數(shù)context.go(’/search?keyword=myName’)目標(biāo)頁面可以得到參數(shù)myName
ElevatedButton(
onPressed: () => context.go('/search?keyword=myName'),
child: const Text('Go to the Search screen'),
),
五、添加子路由
子路由,路由匹配支持多個頁面,當(dāng)一個新的頁面在舊的頁面之上展示時
GoRoute(
path: 'details',
builder: (BuildContext context, GoRouterState state) {
return const DetailsScreen();
},
routes:
// 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’)來進(jìn)行調(diào)用
ElevatedButton(
onPressed: () => context.go('/details/sub-details'),
child: const Text('Go to the SubDetails screen'),
),
六、頁面導(dǎo)航
go_router提供多種方式進(jìn)行跳轉(zhuǎn)
context.goNamed方式
ElevatedButton(
onPressed: () => context.goNamed('/details'),
child: const Text('Go to the Details screen'),
),
七、路由重定向
go_router提供全局重定向,比如在沒有登錄的用戶,需要跳轉(zhuǎn)到登錄頁面.在 GoRouter 中,可以通過redirect 參數(shù)配置重定向.
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定義了默認(rèn)的錯誤頁面,也可以通過 errorBuilder 參數(shù)自定義錯誤頁面。
errorBuilder: (
BuildContext context,
GoRouterState state,
) {
// ErrorPage
return ErrorScreen();
}
九、路由跳轉(zhuǎn)監(jiān)測
在flutter自帶的會有NavigatorObserver,go_router頁提供路由跳轉(zhuǎn)監(jiān)測功能
class MyNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route
print('did push route');
}
@override
void didPop(Route
print('did pop route');
}
}
在observers中配置
GoRouter(
observers: [MyNavigatorObserver()],
...
)
這里只是代碼嘗試了一下常用功能。還有一些轉(zhuǎn)場動畫、嵌套導(dǎo)航等等特性需要去嘗試。 可以查看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
print('did push route');
}
@override
void didPop(Route
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:
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) {
return const HomeScreen();
},
routes:
GoRoute(
path: 'details',
builder: (BuildContext context, GoRouterState state) {
return const DetailsScreen();
},
routes:
// 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'),
),
),
);
}
}
十、小結(jié)
flutter開發(fā)實戰(zhàn)-go_router使用
學(xué)習(xí)記錄,每天不停進(jìn)步。
柚子快報邀請碼778899分享:flutter開發(fā)實戰(zhàn)-go
文章鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。