Flutter导航灵活布局插件nav_flex的使用

Flutter导航灵活布局插件nav_flex的使用

本插件展示了如何在Flutter应用程序中使用动态路由注册系统实现自定义导航系统。它支持自定义过渡动画、路由守卫(用于路由访问控制)以及可拖动的历史按钮来查看和导航历史记录。

功能特性

  • 自定义路由处理:动态注册路由并定义自定义过渡。
  • 导航守卫:设置守卫(中间件)以控制对特定路由的访问。
  • 历史跟踪:跟踪导航历史并返回到之前的路由。
  • 可拖动历史按钮:一个浮动的可拖动按钮,用于显示路由历史。
  • 自定义过渡:支持在路由之间导航时使用自定义过渡动画。

项目结构

  • main.dart:包含主应用配置和导航设置。
  • NavigationService.dart:处理导航逻辑,包括路由推入、弹出以及管理路由历史。
  • CustomNavigatorObserver.dart:自定义的Navigator观察器,用于监控和更新导航历史。
  • DraggableHistoryButton.dart:一个可拖动的浮动按钮,用于显示路由历史并快速导航。

设置步骤

1. 添加路由

可以通过RouteService.addRoute方法动态添加路由。每个路由必须有一个唯一的名称和对应的Widget构建器。还可以选择性地提供一个守卫函数来控制访问。

RouteService.addRoute(
  '/profile',
  (context) => ProfilePage(),
  guard: () async {
    return await AuthService.isAuthenticated();
  },
);

2. 设置初始路由

在创建新的导航服务时,应设置根路由。

NavigationService.addInitialRoute('homePage');

3. 设置根Widget

创建带有初始路由的根Widget。

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: NavigationService.navigatorKey,
      onGenerateRoute: RouteService.onGenerateRoute,
      initialRoute: 'homePage',
      navigatorObservers: [CustomNavigatorObserver()],
    );
  }
}

4. 设置可拖动历史按钮

创建一个自定义覆盖小部件来控制路由堆栈。

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: NavigationService.navigatorKey,
      onGenerateRoute: RouteService.onGenerateRoute,
      initialRoute: 'homePage',
      navigatorObservers: [CustomNavigatorObserver()],
      builder: (context, child) {
        return Stack(
          children: [
            if (child != null) child,
            const DraggableHistoryButton(), // 浮动历史按钮
          ],
        );
      },
    );
  }
}

导航守卫

可以为路由添加守卫以进行访问控制。例如,DetailsPageHistoryPage添加了一个守卫来模拟访问控制:

RouteService.addRoute(
  'historyPage',
  (context) => const HistoryPage(),
  guard: () async {
    final hasAccess = await checkAdminAccess();
    if (!hasAccess) {
      print("Access Denied to Admin Page");
    }
    return hasAccess;
  },
);

使用方法

1. 推入路由

ElevatedButton(
  onPressed: () {
    NavigationService.push(
      context: context,
      routeName: "detailPage",
      arguments: {'id': 42, 'name': "John"},
      transitionsBuilder: TransitionFactory.slideTransition(),
    );
  },
  child: const Text('Go to Details'),
),

2. 返回到指定路由

ListTile(
  title: Text(routeName),
  onTap: () {
    NavigationService.popUntil(routeName);
  },
);

完整示例代码

以下是完整的示例代码:

import 'package:flutter/material.dart';
import 'package:nav_flex/navigator/nav_flex.dart';

/// 自定义导航系统的演示。
///
/// - 动态路由注册。
/// - 包括访问控制、自定义过渡动画和路由历史跟踪。
///
/// ### 特性:
/// - 带有可选守卫的动态路由添加。
/// - 动画路由过渡(滑动、淡入等)。
/// - 路由历史跟踪和基于历史的导航。
///
/// ### 入口点:
/// - `HomePage`: 主页,包含一个按钮导航到`DetailsPage`。
/// - `DetailsPage`: 显示参数并导航到`HistoryPage`。
/// - `HistoryPage`: 显示导航历史,允许用户返回到任何先前的路由。
void main() {
  // 注册初始路由
  RouteService.addRoute('homePage', (context) => const HomePage());
  RouteService.addRoute('detailPage', (context) => const DetailsPage());

  // 设置初始路由
  NavigationService.addInitialRoute('homePage');

  runApp(const MyApp());
}

/// 应用程序的根小部件。
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: NavigationService.navigatorKey,
      onGenerateRoute: RouteService.onGenerateRoute,
      initialRoute: 'homePage',
      navigatorObservers: [CustomNavigatorObserver()],
      builder: (context, child) {
        return Stack(
          children: [
            if (child != null) child,
            const DraggableHistoryButton(), // 浮动历史按钮
          ],
        );
      },
    );
  }
}

/// 应用程序的主页,提供导航到详细页面的功能。
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            NavigationService.push(
              context: context,
              routeName: "detailPage",
              arguments: {'id': 42, 'name': "John"},
              transitionsBuilder: TransitionFactory.slideTransition(),
            );
          },
          child: const Text('Go to Details'),
        ),
      ),
    );
  }
}

/// 显示接收到的参数并导航到历史页面的详细页面。
class DetailsPage extends StatelessWidget {
  const DetailsPage({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    Future<bool> checkAdminAccess() async {
      await Future.delayed(const Duration(milliseconds: 300));
      return false; // 模拟访问被拒绝
    }

    // 动态添加带守卫的'historyPage'路由
    RouteService.addRoute(
      'historyPage',
      (context) => const HistoryPage(),
      guard: () async {
        final hasAccess = await checkAdminAccess();
        if (!hasAccess) {
          print("Access Denied to Admin Page");
        }
        return hasAccess;
      },
    );

    // 提取传递给此路由的参数
    final map = NavigationService.getCurrentRouteSettings(context)?.arguments
        as Map<String, Object?>?;
    final id = map?['id'];
    final name = map?['name'];

    return Scaffold(
      appBar: AppBar(title: const Text('Details')),
      body: Column(
        children: [
          Center(
            child: Text('Received ID: $id, Name: $name'),
          ),
          Center(
            child: ElevatedButton(
              onPressed: () {
                NavigationService.push(
                  context: context,
                  routeName: "historyPage",
                  transitionsBuilder: TransitionFactory.slideTransition(),
                );
              },
              child: const Text('Show History'),
            ),
          ),
          Text(NavigationService.history.toString()),
        ],
      ),
    );
  }
}

/// 显示导航历史并允许用户返回到先前路由的历史页面。
class HistoryPage extends StatelessWidget {
  const HistoryPage({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('History')),
      body: ListView.builder(
        itemCount: NavigationService.history.length,
        itemBuilder: (context, index) {
          String routeName = NavigationService.history[index];
          return ListTile(
            title: Text(routeName),
            onTap: () {
              NavigationService.popUntil(routeName);
            },
          );
        },
      ),
    );
  }
}

更多关于Flutter导航灵活布局插件nav_flex的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter导航灵活布局插件nav_flex的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


nav_flex 是一个用于 Flutter 的导航和布局插件,旨在提供更灵活的导航和布局管理。它允许开发者以更简洁的方式管理页面导航和布局,特别是在复杂的应用场景中。以下是如何使用 nav_flex 插件的基本指南。

1. 安装插件

首先,你需要在 pubspec.yaml 文件中添加 nav_flex 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  nav_flex: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来安装插件。

2. 基本使用

nav_flex 提供了一个 NavFlex 组件,你可以将其作为应用的根组件来管理导航和布局。

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

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

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: NavFlex(
        initialRoute: '/',
        routes: {
          '/': (context) => HomePage(),
          '/details': (context) => DetailsPage(),
        },
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            NavFlex.of(context).push('/details');
          },
          child: Text('Go to Details'),
        ),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Details')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            NavFlex.of(context).pop();
          },
          child: Text('Go Back'),
        ),
      ),
    );
  }
}

3. 导航管理

NavFlex 提供了多种导航方法,例如 push, pop, replace, popUntil 等。

  • push: 导航到新页面。
  • pop: 返回上一页面。
  • replace: 替换当前页面。
  • popUntil: 返回到指定页面。
// 导航到新页面
NavFlex.of(context).push('/details');

// 返回上一页面
NavFlex.of(context).pop();

// 替换当前页面
NavFlex.of(context).replace('/details');

// 返回到指定页面
NavFlex.of(context).popUntil('/home');

4. 布局管理

NavFlex 还支持灵活的布局管理,允许你在不同的页面之间共享布局组件。例如,你可以在多个页面之间共享一个底部导航栏。

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: NavFlex(
        initialRoute: '/',
        routes: {
          '/': (context) => HomePage(),
          '/details': (context) => DetailsPage(),
        },
        bottomNavigationBar: BottomNavigationBar(
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: 'Home',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.details),
              label: 'Details',
            ),
          ],
          currentIndex: NavFlex.of(context).currentIndex,
          onTap: (index) {
            NavFlex.of(context).setIndex(index);
          },
        ),
      ),
    );
  }
}
回到顶部