Flutter路由钩子插件nav_hooks的使用
Flutter路由钩子插件nav_hooks的使用
提供一种简单的导航方式。包含了许多路由。适用于Android和iOS平台。
安装
在pubspec.yaml
文件中添加nav
依赖:
dependencies:
nav: ^{latest version}
使用
步骤1:在你的AppState中添加Nav
混入
import 'package:nav/nav.dart';
class _MyAppState extends State<MyApp> with Nav
步骤2:重写navigatorKey
方法并提供一个全局键,该键将在MaterialApp
中使用
class MyApp extends StatefulWidget {
static GlobalKey<NavigatorState> navigatorKey = GlobalKey();
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with Nav {
[@override](/user/override)
GlobalKey<NavigatorState> get navigatorKey => MyApp.navigatorKey;
[@override](/user/override)
Widget build(BuildContext context) {
return Material(
textStyle: const TextStyle(color: Colors.black),
child: MaterialApp(
navigatorKey: navigatorKey,
title: 'Nav Demo',
theme: ThemeData(
fontFamily: 'DMSans',
scaffoldBackgroundColor: Colors.white,
iconTheme: const IconThemeData(color: Colors.blue),
textTheme: const TextTheme(),
bottomSheetTheme: const BottomSheetThemeData(backgroundColor: Colors.transparent),
),
home: MyHomePage(),
),
);
}
}
步骤3:使用各种推送方法
// 动态方式
Nav.push(Widget, navAni: NavAni.Blink)
// 或者
Nav.pushFromRight(Widget)
Nav.pushFromLeft(Widget)
Nav.pushFromTop(Widget)
Nav.pushFromBottom(Widget)
Nav.pushReplacement(Widget)
Nav.pushWithRippleEffect(Widget, centerAlignment : Alignment.bottomRight, centerOffset : Offset(10, 10))
Nav.clearAllAndPush(Widget)
enum NavAni { Left, Right, Top, Bottom, Fade, Ripple, Blink }
步骤4:所有方法都可以返回值
// 从底部屏幕返回结果
final result = await Nav.pushFromRight(TopScreen); // 你可以从TopWidget获取结果
// 从顶部屏幕返回结果
Nav.pop(context, result: {"key": "value", "key2": 2})
示例代码
以下是完整的示例代码:
import 'dart:io';
import 'package:after_layout/after_layout.dart';
import 'package:example/enum_direction.dart';
import 'package:example/util/u_color_generator.dart';
import 'package:flutter/material.dart';
import 'package:nav_hooks/nav.dart';
import 'dialog/message_dialog.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
static GlobalKey<NavigatorState> navigatorKey = GlobalKey();
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with Nav {
[@override](/user/override)
GlobalKey<NavigatorState> get navigatorKey => MyApp.navigatorKey;
[@override](/user/override)
Widget build(BuildContext context) {
return Material(
textStyle: const TextStyle(color: Colors.black),
child: MaterialApp(
navigatorKey: navigatorKey,
title: 'Nav Demo',
theme: ThemeData(
fontFamily: 'DMSans',
scaffoldBackgroundColor: Colors.white,
iconTheme: const IconThemeData(color: Colors.blue),
textTheme: const TextTheme(),
bottomSheetTheme: const BottomSheetThemeData(backgroundColor: Colors.transparent),
),
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, this.navType}) : super(key: key);
final NavType? navType;
[@override](/user/override)
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with AfterLayoutMixin {
bool showBackButton = false;
Color? bgColor;
bool get isHome => !showBackButton;
[@override](/user/override)
void initState() {
bgColor = getRandomColor();
super.initState();
}
[@override](/user/override)
void afterFirstLayout(BuildContext context) {
checkCanPop();
}
void checkCanPop() async {
if (await Nav.canPop()) {
setState(() {
this.showBackButton = true;
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bgColor,
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: () async {
await MessageDialog().show();
},
tooltip: 'Ripple',
child: Icon(Icons.open_in_new),
),
),
body: Builder(
builder: (context) => SafeArea(
child: Stack(
children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () async => onResult(
context,
await Nav.pushFromTop(MyHomePage(navType: NavType.Top))),
icon: icon(Icons.vertical_align_bottom),
)
],
),
Expanded(
child: Container(
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () async {
onResult(
context,
await Nav.pushFromLeft(MyHomePage(navType: NavType.Left)));
},
icon: icon(Icons.keyboard_arrow_right),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
InkWell(
child: icon(iconData),
onTap: () {
if (isHome) {
Nav.clearAllAndPush(MyHomePage(navType: NavType.ClearAll));
} else {
Nav.popResultSuccess(context);
}
},
),
isHome
? Text("Click an Arrow",
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w700))
: Container(),
],
),
IconButton(
onPressed: () async => onResult(
context,
await Nav.pushFromRight(MyHomePage(navType: NavType.Right))),
icon: icon(Icons.keyboard_arrow_left),
),
],
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () async => onResult(
context,
await Nav.pushFromBottom(MyHomePage(navType: NavType.Bottom))),
icon: icon(Icons.vertical_align_top),
)
],
),
],
),
!showBackButton
? Container()
: IconButton(
onPressed: () => Nav.pop(context),
icon: icon(Platform.isIOS
? Icons.arrow_back_ios
: Icons.arrow_back),
)
],
),
),
),
);
}
Icon icon(IconData data) {
return Icon(
data,
size: 30,
color: Colors.white,
);
}
IconData get iconData {
switch (widget.navType) {
case NavType.Top:
return Icons.vertical_align_top;
case NavType.Bottom:
return Icons.vertical_align_bottom;
case NavType.Left:
return Icons.keyboard_arrow_left;
case NavType.Right:
return Icons.keyboard_arrow_right;
case NavType.Ripple:
return Icons.archive;
case NavType.ClearAll:
return Icons.border_clear;
default:
return Icons.home;
}
}
SnackBar createSnackBar(BuildContext context, String message) {
return SnackBar(
elevation: 0,
behavior: SnackBarBehavior.fixed,
backgroundColor: Colors.transparent,
content: GestureDetector(
onTap: () {},
child: Container(
color: Colors.transparent,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Center(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 11),
child: Center(
child: Text(message,
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontStyle: FontStyle.normal,
)),
),
decoration: new BoxDecoration(
color: Color(0xff5a8fee),
borderRadius: BorderRadius.circular(5))),
),
],
),
),
));
}
void onResult(BuildContext context, dynamic result) {
if (Nav.isSuccess(result)) {
final snackbar =
createSnackBar(context, "Result is Success: ${result.toString()}");
ScaffoldMessenger.of(context).showSnackBar(snackbar);
}
}
}
更多关于Flutter路由钩子插件nav_hooks的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复
更多关于Flutter路由钩子插件nav_hooks的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
nav_hooks
是一个用于 Flutter 的路由钩子插件,它允许你在导航过程中执行一些自定义逻辑。通过使用 nav_hooks
,你可以在路由跳转前后执行特定的操作,例如权限验证、日志记录、数据预处理等。
安装
首先,你需要将 nav_hooks
添加到你的 pubspec.yaml
文件中:
dependencies:
flutter:
sdk: flutter
nav_hooks: ^1.0.0 # 请查看最新版本
然后运行 flutter pub get
来安装依赖。
基本用法
1. 创建路由钩子
你可以通过继承 RouteHook
类来创建自定义的路由钩子。RouteHook
提供了以下几个生命周期方法:
beforeNavigate
: 在导航之前调用。afterNavigate
: 在导航之后调用。beforePop
: 在返回之前调用。afterPop
: 在返回之后调用。
import 'package:nav_hooks/nav_hooks.dart';
class AuthRouteHook extends RouteHook {
@override
FutureOr<bool> beforeNavigate(BuildContext context, RouteSettings settings) async {
// 在导航之前执行的逻辑,例如权限检查
bool isAuthenticated = await checkAuth();
if (!isAuthenticated) {
// 如果用户未认证,重定向到登录页面
Navigator.pushNamed(context, '/login');
return false; // 阻止原路由的跳转
}
return true; // 允许继续导航
}
@override
void afterNavigate(BuildContext context, RouteSettings settings) {
// 在导航之后执行的逻辑,例如日志记录
print('Navigated to: ${settings.name}');
}
@override
FutureOr<bool> beforePop(BuildContext context, RouteSettings settings) async {
// 在返回之前执行的逻辑
bool shouldPop = await showConfirmationDialog();
return shouldPop; // 允许或阻止返回
}
@override
void afterPop(BuildContext context, RouteSettings settings) {
// 在返回之后执行的逻辑
print('Popped from: ${settings.name}');
}
}
2. 使用路由钩子
你可以在 MaterialApp
或 CupertinoApp
中使用 NavigatorHooks
来应用路由钩子。
import 'package:flutter/material.dart';
import 'package:nav_hooks/nav_hooks.dart';
import 'auth_route_hook.dart'; // 导入自定义的路由钩子
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Nav Hooks Demo',
navigatorKey: NavigatorHooks.navigatorKey,
navigatorObservers: [
NavigatorHooks(
hooks: [AuthRouteHook()], // 添加路由钩子
),
],
initialRoute: '/',
routes: {
'/': (context) => HomePage(),
'/login': (context) => LoginPage(),
'/dashboard': (context) => DashboardPage(),
},
);
}
}
高级用法
你还可以在特定的路由上应用不同的路由钩子,或者根据条件动态地应用钩子。
NavigatorHooks(
hooks: [
AuthRouteHook(), // 全局钩子
RouteHookBuilder(
shouldApply: (settings) => settings.name == '/dashboard',
builder: () => DashboardRouteHook(), // 仅在 '/dashboard' 路由上应用的钩子
),
],
);