router_pro 0.2.0 copy "router_pro: ^0.2.0" to clipboard
router_pro: ^0.2.0 copied to clipboard

Enhanced Flutter router with lifecycle awareness, launch modes, route guards, and more.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:router_pro/router_lib.dart';
import 'visibility_example.dart';

/// Router Pro 完整示例
/// 包含所有功能演示:
/// 1. 路由启动模式
/// 2. 路由守卫
/// 3. 命名路由值回调
/// 4. 404错误页面
/// 5. 生命周期感知
/// 6. 可见性检测

void main() {
  // 初始化路由
  initRouter();
  runApp(const MyApp());
}

// 全局路由实例
late RouterProxy router;

// 模拟登录状态
bool _isLoggedIn = false;

void initRouter() {
  router = RouterProxy.getInstance(
    pageMap: {
      '/': const HomePage(),
      '/login': const LoginPage(),
      '/profile': const ProfilePage(),
      '/settings': const SettingsPage(),
      '/visibility': const VisibilityExamplePage(),
      '/lazy-image': const LazyImageExample(),
      '/auto-video': const AutoPlayVideoExample(),
      '/exposure': const ExposureTrackingExample(),
    },
    notFoundPage: const NotFoundPage(),
    exitWindow: _confirmExit,
    routePathCallBack: (routeInfo) {
      // 动态路由回调 - 用于处理路径参数
      final path = routeInfo.uri.path;
      
      // 从 state 中获取解析后的参数
      final params = RouteParams.fromState(routeInfo.state);
      
      if (params != null) {
        // /user/:id - 用户详情
        if (params.matchedPattern == '/user/:id') {
          final userId = params.getPathParam('id');
          return UserDetailPage(userId: userId!);
        }
        
        // /product/:category/:id - 商品详情
        if (params.matchedPattern == '/product/:category/:id') {
          final category = params.getPathParam('category');
          final productId = params.getPathParam('id');
          final color = params.getQueryParam('color');
          final size = params.getQueryParam('size');
          return ProductDetailPage(
            category: category!,
            productId: productId!,
            color: color,
            size: size,
          );
        }
        
        // /search?q=keyword&page=1 - 搜索结果
        if (path == '/search') {
          final keyword = params.getQueryParam('q');
          final page = params.getQueryParam('page');
          return SearchResultPage(
            keyword: keyword ?? '',
            page: int.tryParse(page ?? '1') ?? 1,
          );
        }
      }
      
      return null;
    },
  );

  // 添加命名路由守卫 - 用于 pushNamed 方式
  router.addRouteGuard((from, to) async {
    final protectedRoutes = ['/profile'];
    
    if (protectedRoutes.contains(to.uri.toString()) && !_isLoggedIn) {
      debugPrint('路由守卫: 拦截命名路由 ${to.uri},需要登录');
      router.pushNamed(name: '/login');
      return false;
    }
    return true;
  });

  // 添加页面类型守卫 - 用于 push(page: xxx) 方式
  router.addPageTypeGuard((fromPageType, toPageType) async {
    final protectedPageTypes = [
      VideoPlayerDemoPage,
      ProfileDetailPage,
    ];
    
    if (protectedPageTypes.contains(toPageType) && !_isLoggedIn) {
      debugPrint('页面类型守卫: 拦截页面类型 $toPageType,需要登录');
      // 这里不能直接 push LoginPage,因为会触发循环,所以用 pushNamed
      router.pushNamed(name: '/login');
      return false;
    }
    return true;
  });
}

Future<bool> _confirmExit(BuildContext context) async {
  final result = await showDialog<bool>(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('退出确认'),
      content: const Text('确定要退出应用吗?'),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context, true),
          child: const Text('取消'),
        ),
        TextButton(
          onPressed: () => Navigator.pop(context, false),
          child: const Text('确定'),
        ),
      ],
    ),
  );
  return result ?? true;
}

// 切换登录状态的辅助函数
void toggleLoginStatus() {
  _isLoggedIn = !_isLoggedIn;
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 创建增强的路由解析器
    final parser = EnhancedParser(
      enablePathParams: true,
      enableQueryParams: true,
      routeAliases: {
        '/home': '/',
      },
      patterns: [
        RoutePattern('/user/:id'),
        RoutePattern('/product/:category/:id'),
      ],
    );

    return MaterialApp.router(
      title: 'Router Pro - 完整示例',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      routerDelegate: router,
      routeInformationParser: parser, // 使用增强的解析器
    );
  }
}

// ============ 首页 ============
class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // 创建 GlobalKey 和 DrawerStackController
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  late final DrawerStackController controller;

  @override
  void initState() {
    super.initState();
    
    // 使用新的 DrawerStackController API
    controller = DrawerStackController(
      scaffoldKey: _scaffoldKey,
      routerProxy: RouterProxy.getDrawerInstance(
        stackId: 'main-drawer',
        pageMap: {
          '/': const DrawerHomePage(),
          '/drawer-settings': const DrawerSettingsPage(),
          '/drawer-profile': const DrawerProfilePage(),
        },
      ),
      config: const DrawerConfig(
        autoOpen: true,
        autoClose: true,
        isEndDrawer: true,
      ),
    );
  }

  @override
  void dispose() {
    // 清理 DrawerStackController 资源
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return LifeCycle(
      debugLabel: 'HomePage',
      onCreate: () => debugPrint('HomePage onCreate'),
      onResume: () => debugPrint('HomePage onResume'),
      onPause: () => debugPrint('HomePage onPause'),
      child: Scaffold(
        key: _scaffoldKey, // 传入 GlobalKey
        appBar: AppBar(
          title: const Text('Router Pro 完整示例'),
          centerTitle: true,
          actions: [
            // 登录状态切换按钮
            IconButton(
              icon: Icon(_isLoggedIn ? Icons.logout : Icons.login),
              tooltip: _isLoggedIn ? '退出登录' : '登录',
              onPressed: () {
                setState(() {
                  toggleLoginStatus();
                });
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(
                    content: Text(_isLoggedIn ? '已登录' : '已退出登录'),
                    duration: const Duration(seconds: 1),
                  ),
                );
              },
            ),
          ],
        ),
        // 使用新的 DrawerNavigator Widget,样式由外层 Container 控制
        endDrawer: Container(
          width: 300,
          color: Colors.white,
          child: DrawerNavigator(controller: controller),
        ),
        body: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            // 登录状态显示
            Card(
              color: _isLoggedIn ? Colors.green.shade50 : Colors.orange.shade50,
              child: Padding(
                padding: const EdgeInsets.all(16),
                child: Row(
                  children: [
                    Icon(
                      _isLoggedIn ? Icons.check_circle : Icons.info,
                      color: _isLoggedIn ? Colors.green : Colors.orange,
                    ),
                    const SizedBox(width: 12),
                    Text(
                      _isLoggedIn ? '当前状态:已登录' : '当前状态:未登录',
                      style: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),
            
            _buildSectionTitle('🚀 路由功能'),
            _buildFeatureCard(
              icon: Icons.layers,
              title: '路由启动模式',
              description: '演示 Standard、SingleTop、SingleInstance 三种模式',
              onTap: () => _showLaunchModeDemo(context),
            ),
            _buildFeatureCard(
              icon: Icons.security,
              title: '路由守卫(命名路由)',
              description: '演示命名路由拦截和权限验证',
              onTap: () => router.pushNamed(name: '/profile'),
            ),
            _buildFeatureCard(
              icon: Icons.shield,
              title: '页面类型守卫',
              description: '演示 push(page: xxx) 方式的路由守卫',
              onTap: () => router.push(page: const ProfileDetailPage()),
            ),
            _buildFeatureCard(
              icon: Icons.swap_calls,
              title: '命名路由值回调',
              description: '演示通过命名路由传递和接收数据',
              onTap: () => _showValueReturnDemo(context),
            ),
            _buildFeatureCard(
              icon: Icons.menu,
              title: '抽屉路由栈',
              description: '演示抽屉内的独立路由栈管理',
              onTap: () {
                // 打开抽屉并跳转到设置页
                controller.pushNamed(name: '/drawer-settings');
              },
            ),
            _buildFeatureCard(
              icon: Icons.error_outline,
              title: '404错误页面',
              description: '访问不存在的路由',
              onTap: () => router.pushNamed(name: '/not-exist'),
            ),
            const SizedBox(height: 16),
            _buildSectionTitle('🔗 路由解析器'),
            _buildFeatureCard(
              icon: Icons.link,
              title: '增强路由解析器',
              description: '演示路径参数、查询参数、路由别名等功能',
              onTap: () => router.push(page: const EnhancedParserDemoPage()),
            ),
            const SizedBox(height: 16),
            _buildSectionTitle('🔄 生命周期功能'),
            _buildFeatureCard(
              icon: Icons.video_library,
              title: '视频播放生命周期',
              description: '演示视频播放的生命周期管理(需要登录)',
              onTap: () => _showVideoLifecycleDemo(context),
            ),
            const SizedBox(height: 16),
            _buildSectionTitle('👁 可见性检测'),
            _buildFeatureCard(
              icon: Icons.visibility,
              title: '可见性检测示例',
              description: '演示列表项可见性监听',
              onTap: () => router.pushNamed(name: '/visibility'),
            ),
            _buildFeatureCard(
              icon: Icons.image,
              title: '懒加载图片',
              description: '演示图片懒加载',
              onTap: () => router.pushNamed(name: '/lazy-image'),
            ),
            _buildFeatureCard(
              icon: Icons.play_circle,
              title: '视频自动播放',
              description: '演示视频自动播放/暂停',
              onTap: () => router.pushNamed(name: '/auto-video'),
            ),
            _buildFeatureCard(
              icon: Icons.analytics,
              title: '曝光统计',
              description: '演示商品曝光统计',
              onTap: () => router.pushNamed(name: '/exposure'),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSectionTitle(String title) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Text(
        title,
        style: const TextStyle(
          fontSize: 20,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }

  Widget _buildFeatureCard({
    required IconData icon,
    required String title,
    required String description,
    required VoidCallback onTap,
  }) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: ListTile(
        leading: Icon(icon, size: 32, color: Colors.blue),
        title: Text(
          title,
          style: const TextStyle(fontWeight: FontWeight.bold),
        ),
        subtitle: Text(description),
        trailing: const Icon(Icons.arrow_forward_ios, size: 16),
        onTap: onTap,
      ),
    );
  }

  void _showLaunchModeDemo(BuildContext context) {
    showModalBottomSheet(
      context: context,
      builder: (context) => Container(
        padding: const EdgeInsets.all(16),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const Text(
              '选择启动模式',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 16),
            ListTile(
              leading: const Icon(Icons.layers),
              title: const Text('Standard 标准模式'),
              subtitle: const Text('可创建多个实例'),
              onTap: () {
                Navigator.pop(context);
                router.push(
                  page: const DetailPage(title: '标准模式'),
                  launchMode: LaunchMode.standard,
                );
              },
            ),
            ListTile(
              leading: const Icon(Icons.vertical_align_top),
              title: const Text('SingleTop 栈顶复用'),
              subtitle: const Text('栈顶已存在则更新参数(类似Android onNewIntent)'),
              onTap: () {
                Navigator.pop(context);
                router.push(
                  page: DetailPage(title: '栈顶复用 - ${DateTime.now().second}秒'),
                  launchMode: LaunchMode.singleTop,
                );
              },
            ),
            ListTile(
              leading: const Icon(Icons.filter_1),
              title: const Text('SingleInstance 单例模式'),
              subtitle: const Text('全栈唯一实例,清除上层页面'),
              onTap: () {
                Navigator.pop(context);
                router.push(
                  page: SingleInstanceDemoPage(timestamp: DateTime.now().toString()),
                  launchMode: LaunchMode.singleInstance,
                );
              },
            ),
          ],
        ),
      ),
    );
  }

  void _showValueReturnDemo(BuildContext context) {
    router.pushNamed(
      name: '/settings',
      onResult: (value) {
        router.showAppSnackBar(message:value);
      },
    );
  }

  void _showVideoLifecycleDemo(BuildContext context) {
    router.push(page: const VideoPlayerDemoPage());
  }
}

// ============ 详情页 ============
class DetailPage extends StatelessWidget {
  final String title;

  const DetailPage({Key? key, required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              title,
              style: const TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                router.push(
                  page: DetailPage(title: '$title - 子页面'),
                );
              },
              child: const Text('继续跳转'),
            ),
          ],
        ),
      ),
    );
  }
}

// ============ 登录页 ============
class LoginPage extends StatelessWidget {
  const LoginPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('登录')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.lock_outline, size: 80, color: Colors.blue),
            const SizedBox(height: 20),
            const Text(
              '请先登录',
              style: TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 40),
            ElevatedButton.icon(
              onPressed: () {
                // 模拟登录成功
                router.pop();
              },
              icon: const Icon(Icons.login),
              label: const Text('登录'),
            ),
          ],
        ),
      ),
    );
  }
}

// ============ 个人中心 ============
class ProfilePage extends StatelessWidget {
  const ProfilePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('个人中心')),
      body: const Center(
        child: Text('个人中心页面'),
      ),
    );
  }
}

// ============ 设置页 ============
class SettingsPage extends StatelessWidget {
  const SettingsPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('设置'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () {
            // 返回时携带数据
            router.pop('设置已保存');
          },
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('设置页面'),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                router.pop('用户点击了保存按钮');
              },
              child: const Text('保存并返回'),
            ),
          ],
        ),
      ),
    );
  }
}

// ============ 404页面 ============
class NotFoundPage extends StatelessWidget {
  const NotFoundPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('页面未找到')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.error_outline, size: 100, color: Colors.red),
            const SizedBox(height: 20),
            const Text(
              '404',
              style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 10),
            const Text('抱歉,您访问的页面不存在'),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: () => router.goRootPage(),
              child: const Text('返回首页'),
            ),
          ],
        ),
      ),
    );
  }
}

// ============ 视频播放演示页 ============
class VideoPlayerDemoPage extends StatefulWidget {
  const VideoPlayerDemoPage({Key? key}) : super(key: key);

  @override
  State<VideoPlayerDemoPage> createState() => _VideoPlayerDemoPageState();
}

class _VideoPlayerDemoPageState extends State<VideoPlayerDemoPage> {
  bool _isPlaying = false;

  @override
  Widget build(BuildContext context) {
    return LifeCycle(
      visibilityThreshold: 0.8,
      debugLabel: 'VideoPlayer',
      onResume: () {
        setState(() => _isPlaying = true);
        debugPrint('视频开始播放');
      },
      onPause: () {
        setState(() => _isPlaying = false);
        debugPrint('视频暂停');
      },
      onDestroy: () {
        debugPrint('视频资源释放');
      },
      child: Scaffold(
        appBar: AppBar(
          title: const Text('视频播放生命周期'),
          leading: IconButton(
            icon: const Icon(Icons.arrow_back),
            onPressed: () => router.pop(),
          ),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: 300,
                height: 200,
                decoration: BoxDecoration(
                  color: Colors.black,
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Center(
                  child: Icon(
                    _isPlaying ? Icons.play_circle_filled : Icons.pause_circle_filled,
                    size: 64,
                    color: Colors.white,
                  ),
                ),
              ),
              const SizedBox(height: 20),
              Text(
                _isPlaying ? '播放中...' : '已暂停',
                style: const TextStyle(fontSize: 18),
              ),
              const SizedBox(height: 10),
              const Text(
                '页面80%可见时自动播放\n页面不可见时自动暂停',
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.grey),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// ============ 个人详情页(用于演示页面类型守卫) ===========
class ProfileDetailPage extends StatelessWidget {
  const ProfileDetailPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('个人详情'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.person, size: 80, color: Colors.blue),
            const SizedBox(height: 20),
            const Text(
              '个人详情页面',
              style: TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 10),
            const Text(
              '此页面通过页面类型守卫保护',
              style: TextStyle(color: Colors.grey),
            ),
            const SizedBox(height: 10),
            const Text(
              '使用 router.push(page: ProfileDetailPage()) 跳转',
              style: TextStyle(color: Colors.grey, fontSize: 12),
            ),
          ],
        ),
      ),
    );
  }
}

// ============ SingleInstance 演示页 ============
class SingleInstanceDemoPage extends StatelessWidget {
  final String timestamp;
  
  const SingleInstanceDemoPage({
    Key? key,
    required this.timestamp,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SingleInstance 演示'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Icon(
                Icons.filter_1,
                size: 80,
                color: Colors.blue,
              ),
              const SizedBox(height: 20),
              const Text(
                'SingleInstance 模式',
                style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 10),
              Text(
                '创建时间: $timestamp',
                style: const TextStyle(color: Colors.grey),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 30),
              const Text(
                '特点:',
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 10),
              const Text(
                '• 全局唯一实例\n'
                '• 已存在时更新参数\n'
                '• 清除该页面上面的所有页面\n'
                '• 适用于购物车、首页等场景',
                style: TextStyle(fontSize: 14),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 40),
              ElevatedButton.icon(
                onPressed: () {
                  router.push(page: const IntermediatePage());
                },
                icon: const Icon(Icons.add),
                label: const Text('添加中间页面'),
              ),
              const SizedBox(height: 10),
              ElevatedButton.icon(
                onPressed: () {
                  router.push(
                    page: SingleInstanceDemoPage(
                      timestamp: DateTime.now().toString(),
                    ),
                    launchMode: LaunchMode.singleInstance,
                  );
                },
                icon: const Icon(Icons.refresh),
                label: const Text('再次启动(会清除中间页面)'),
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.orange,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// ============ 中间页面(用于演示 SingleInstance 清除效果) ===========
class IntermediatePage extends StatelessWidget {
  const IntermediatePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('中间页面'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.layers, size: 80, color: Colors.green),
            const SizedBox(height: 20),
            const Text(
              '这是一个中间页面',
              style: TextStyle(fontSize: 20),
            ),
            const SizedBox(height: 10),
            const Text(
              '当再次启动 SingleInstance 页面时\n这个页面会被清除',
              style: TextStyle(color: Colors.grey),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: () {
                router.push(page: const IntermediatePage());
              },
              child: const Text('再添加一个中间页面'),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: () {
                router.push(
                  page: SingleInstanceDemoPage(
                    timestamp: DateTime.now().toString(),
                  ),
                  launchMode: LaunchMode.singleInstance,
                );
              },
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.orange,
              ),
              child: const Text('返回 SingleInstance 页面'),
            ),
          ],
        ),
      ),
    );
  }
}

// ============ 增强路由解析器演示页 ============
class EnhancedParserDemoPage extends StatelessWidget {
  const EnhancedParserDemoPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('增强路由解析器示例'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          const Card(
            color: Colors.blue,
            child: Padding(
              padding: EdgeInsets.all(16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    '💡 提示',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  SizedBox(height: 8),
                  Text(
                    '本示例演示 EnhancedParser 的功能:\n'
                    '• 路径参数解析 (/user/:id)\n'
                    '• 查询参数解析 (?key=value)\n'
                    '• 路由别名 (/home -> /)\n'
                    '• 混合使用',
                    style: TextStyle(color: Colors.white),
                  ),
                ],
              ),
            ),
          ),
          const SizedBox(height: 20),
          const Text(
            '路径参数示例',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 10),
          _buildExampleCard(
            title: '用户详情',
            description: '路径: /user/:id',
            example: '示例: /user/123',
            onTap: () {
              router.pushNamed(name: '/user/123');
            },
          ),
          _buildExampleCard(
            title: '商品详情',
            description: '路径: /product/:category/:id',
            example: '示例: /product/electronics/456',
            onTap: () {
              router.pushNamed(name: '/product/electronics/456');
            },
          ),
          const SizedBox(height: 20),
          const Text(
            '查询参数示例',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 10),
          _buildExampleCard(
            title: '搜索结果',
            description: '路径: /search?q=keyword&page=1',
            example: '示例: /search?q=Flutter&page=2',
            onTap: () {
              router.pushNamed(name: '/search?q=Flutter&page=2');
            },
          ),
          _buildExampleCard(
            title: '商品详情(带查询参数)',
            description: '路径: /product/:category/:id?color=red',
            example: '示例: /product/electronics/456?color=red&size=large',
            onTap: () {
              router.pushNamed(
                name: '/product/electronics/456?color=red&size=large',
              );
            },
          ),
        ],
      ),
    );
  }

  Widget _buildExampleCard({
    required String title,
    required String description,
    required String example,
    required VoidCallback onTap,
  }) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: ListTile(
        title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
        subtitle: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const SizedBox(height: 4),
            Text(description),
            const SizedBox(height: 2),
            Text(
              example,
              style: const TextStyle(
                fontFamily: 'monospace',
                fontSize: 12,
                color: Colors.blue,
              ),
            ),
          ],
        ),
        trailing: const Icon(Icons.arrow_forward_ios, size: 16),
        onTap: onTap,
      ),
    );
  }
}

// ============ 用户详情页(路径参数示例) ===========
class UserDetailPage extends StatelessWidget {
  final String userId;

  const UserDetailPage({Key? key, required this.userId}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('用户详情 #$userId'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.person, size: 80, color: Colors.blue),
            const SizedBox(height: 20),
            Text(
              '用户 ID: $userId',
              style: const TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 10),
            const Text(
              '✓ 路径参数已成功解析',
              style: TextStyle(color: Colors.green, fontSize: 16),
            ),
            const SizedBox(height: 10),
            const Text(
              '路径: /user/:id',
              style: TextStyle(
                color: Colors.grey,
                fontFamily: 'monospace',
              ),
            ),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: () => router.pop(),
              child: const Text('返回'),
            ),
          ],
        ),
      ),
    );
  }
}

// ============ 商品详情页(路径参数 + 查询参数示例) ===========
class ProductDetailPage extends StatelessWidget {
  final String category;
  final String productId;
  final String? color;
  final String? size;

  const ProductDetailPage({
    Key? key,
    required this.category,
    required this.productId,
    this.color,
    this.size,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('商品详情 #$productId'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Icon(Icons.shopping_bag, size: 80, color: Colors.blue),
              const SizedBox(height: 20),
              Text(
                '商品 ID: $productId',
                style: const TextStyle(fontSize: 24),
              ),
              const SizedBox(height: 10),
              Text(
                '分类: $category',
                style: const TextStyle(fontSize: 18, color: Colors.grey),
              ),
              if (color != null) ...[
                const SizedBox(height: 10),
                Text(
                  '颜色: $color',
                  style: const TextStyle(fontSize: 18, color: Colors.grey),
                ),
              ],
              if (size != null) ...[
                const SizedBox(height: 10),
                Text(
                  '尺寸: $size',
                  style: const TextStyle(fontSize: 18, color: Colors.grey),
                ),
              ],
              const SizedBox(height: 20),
              const Text(
                '✓ 路径参数和查询参数已成功解析',
                style: TextStyle(color: Colors.green, fontSize: 16),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 10),
              const Text(
                '路径: /product/:category/:id?color=xxx&size=xxx',
                style: TextStyle(
                  color: Colors.grey,
                  fontFamily: 'monospace',
                  fontSize: 12,
                ),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 30),
              ElevatedButton(
                onPressed: () => router.pop(),
                child: const Text('返回'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// ============ 搜索结果页(查询参数示例) ===========
class SearchResultPage extends StatelessWidget {
  final String keyword;
  final int page;

  const SearchResultPage({
    Key? key,
    required this.keyword,
    this.page = 1,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('搜索: $keyword'),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router.pop(),
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.search, size: 80, color: Colors.blue),
            const SizedBox(height: 20),
            Text(
              '关键词: $keyword',
              style: const TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 10),
            Text(
              '页码: $page',
              style: const TextStyle(fontSize: 18, color: Colors.grey),
            ),
            const SizedBox(height: 20),
            const Text(
              '✓ 查询参数已成功解析',
              style: TextStyle(color: Colors.green, fontSize: 16),
            ),
            const SizedBox(height: 10),
            const Text(
              '路径: /search?q=xxx&page=xxx',
              style: TextStyle(
                color: Colors.grey,
                fontFamily: 'monospace',
              ),
            ),
            const SizedBox(height: 30),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                if (page > 1)
                  ElevatedButton(
                    onPressed: () {
                      router.pushNamed(
                        name: '/search?q=$keyword&page=${page - 1}',
                      );
                    },
                    child: const Text('上一页'),
                  ),
                const SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () {
                    router.pushNamed(
                      name: '/search?q=$keyword&page=${page + 1}',
                    );
                  },
                  child: const Text('下一页'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}


// ============ 抽屉路由栈页面 ============

/// 抽屉首页
class DrawerHomePage extends StatelessWidget {
  const DrawerHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 使用 InheritedDrawerStackController 获取 DrawerStackController
    final controller = InheritedDrawerStackController.of(context);
    
    return Column(
      children: [
        // 抽屉头部
        Container(
          width: double.infinity,
          padding: const EdgeInsets.all(20),
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: [Colors.blue.shade700, Colors.blue.shade500],
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
            ),
          ),
          child: SafeArea(
            bottom: false,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    const Text(
                      '抽屉路由栈',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 24,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    IconButton(
                      icon: const Icon(Icons.close, color: Colors.white),
                      onPressed: () => controller?.closeDrawer(),
                    ),
                  ],
                ),
                const SizedBox(height: 8),
                const Text(
                  '独立的路由栈管理',
                  style: TextStyle(
                    color: Colors.white70,
                    fontSize: 14,
                  ),
                ),
              ],
            ),
          ),
        ),
        
        // 菜单列表
        Expanded(
          child: ListView(
            padding: EdgeInsets.zero,
            children: [
              _buildDrawerTile(
                icon: Icons.settings,
                title: '设置',
                subtitle: '应用设置和偏好',
                onTap: () {
                  controller?.push(page: const DrawerSettingsPage());
                },
              ),
              _buildDrawerTile(
                icon: Icons.person,
                title: '个人资料',
                subtitle: '查看和编辑个人信息',
                onTap: () {
                  controller?.push(page: const DrawerProfilePage());
                },
              ),
              _buildDrawerTile(
                icon: Icons.notifications,
                title: '通知',
                subtitle: '消息和提醒',
                onTap: () {
                  controller?.push(page: const DrawerNotificationPage());
                },
              ),
              const Divider(),
              _buildDrawerTile(
                icon: Icons.info,
                title: '关于',
                subtitle: '应用信息和版本',
                onTap: () {
                  controller?.push(page: const DrawerAboutPage());
                },
              ),
              _buildDrawerTile(
                icon: Icons.help,
                title: '帮助',
                subtitle: '使用指南和常见问题',
                onTap: () {
                  controller?.push(page: const DrawerHelpPage());
                },
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildDrawerTile({
    required IconData icon,
    required String title,
    required String subtitle,
    required VoidCallback onTap,
  }) {
    return ListTile(
      leading: Icon(icon, color: Colors.blue),
      title: Text(title),
      subtitle: Text(subtitle, style: const TextStyle(fontSize: 12)),
      trailing: const Icon(Icons.chevron_right),
      onTap: onTap,
    );
  }
}

/// 抽屉设置页
class DrawerSettingsPage extends StatelessWidget {
  const DrawerSettingsPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 使用 InheritedDrawerStackController 获取 DrawerStackController
    final controller = InheritedDrawerStackController.of(context);
    
    return Column(
      children: [
        AppBar(
          title: const Text('设置'),
          leading: IconButton(
            icon: const Icon(Icons.arrow_back),
            onPressed: () => controller?.pop(),
          ),
          actions: [
            IconButton(
              icon: const Icon(Icons.close),
              onPressed: () => controller?.closeDrawer(),
            ),
          ],
        ),
        Expanded(
          child: ListView(
            children: [
              _buildSettingSection(
                title: '通用设置',
                items: [
                  _buildSettingTile(
                    icon: Icons.language,
                    title: '语言',
                    subtitle: '简体中文',
                    onTap: () {
                      controller?.push(page: const DrawerLanguagePage());
                    },
                  ),
                  _buildSettingTile(
                    icon: Icons.palette,
                    title: '主题',
                    subtitle: '跟随系统',
                    onTap: () {
                      controller?.push(page: const DrawerThemePage());
                    },
                  ),
                ],
              ),
              _buildSettingSection(
                title: '隐私设置',
                items: [
                  _buildSettingTile(
                    icon: Icons.lock,
                    title: '隐私',
                    subtitle: '管理隐私选项',
                    onTap: () {
                      controller?.push(page: const DrawerPrivacyPage());
                    },
                  ),
                  _buildSettingTile(
                    icon: Icons.security,
                    title: '安全',
                    subtitle: '密码和安全设置',
                    onTap: () {
                      controller?.push(page: const DrawerSecurityPage());
                    },
                  ),
                ],
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildSettingSection({
    required String title,
    required List<Widget> items,
  }) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
          child: Text(
            title,
            style: const TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.bold,
              color: Colors.grey,
            ),
          ),
        ),
        ...items,
      ],
    );
  }

  Widget _buildSettingTile({
    required IconData icon,
    required String title,
    required String subtitle,
    required VoidCallback onTap,
  }) {
    return ListTile(
      leading: Icon(icon),
      title: Text(title),
      subtitle: Text(subtitle),
      trailing: const Icon(Icons.chevron_right),
      onTap: onTap,
    );
  }
}

/// 抽屉个人资料页
class DrawerProfilePage extends StatelessWidget {
  const DrawerProfilePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 使用 InheritedDrawerStackController 获取 DrawerStackController
    final controller = InheritedDrawerStackController.of(context);
    
    return Column(
      children: [
        AppBar(
          title: const Text('个人资料'),
          leading: IconButton(
            icon: const Icon(Icons.arrow_back),
            onPressed: () => controller?.pop(),
          ),
          actions: [
            IconButton(
              icon: const Icon(Icons.edit),
              onPressed: () {
                controller?.push(page: const DrawerEditProfilePage());
              },
            ),
          ],
        ),
        Expanded(
          child: ListView(
            padding: const EdgeInsets.all(16),
            children: [
              const Center(
                child: CircleAvatar(
                  radius: 50,
                  child: Icon(Icons.person, size: 50),
                ),
              ),
              const SizedBox(height: 16),
              const Center(
                child: Text(
                  '用户名',
                  style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                ),
              ),
              const SizedBox(height: 8),
              const Center(
                child: Text(
                  'user@example.com',
                  style: TextStyle(color: Colors.grey),
                ),
              ),
              const SizedBox(height: 32),
              _buildInfoCard('手机号', '+86 138 0000 0000'),
              _buildInfoCard('生日', '1990-01-01'),
              _buildInfoCard('地址', '北京市朝阳区'),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildInfoCard(String label, String value) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
            Text(value, style: const TextStyle(color: Colors.grey)),
          ],
        ),
      ),
    );
  }
}

// 其他抽屉子页面(简化实现)
class DrawerNotificationPage extends StatelessWidget {
  const DrawerNotificationPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '通知', Icons.notifications);
  }
}

class DrawerAboutPage extends StatelessWidget {
  const DrawerAboutPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '关于', Icons.info);
  }
}

class DrawerHelpPage extends StatelessWidget {
  const DrawerHelpPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '帮助', Icons.help);
  }
}

class DrawerLanguagePage extends StatelessWidget {
  const DrawerLanguagePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '语言设置', Icons.language);
  }
}

class DrawerThemePage extends StatelessWidget {
  const DrawerThemePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '主题设置', Icons.palette);
  }
}

class DrawerPrivacyPage extends StatelessWidget {
  const DrawerPrivacyPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '隐私设置', Icons.lock);
  }
}

class DrawerSecurityPage extends StatelessWidget {
  const DrawerSecurityPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '安全设置', Icons.security);
  }
}

class DrawerEditProfilePage extends StatelessWidget {
  const DrawerEditProfilePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final controller = InheritedDrawerStackController.of(context);
    return _buildSimplePage(controller, '编辑资料', Icons.edit);
  }
}

Widget _buildSimplePage(DrawerStackController? router, String title, IconData icon) {
  return Column(
    children: [
      AppBar(
        title: Text(title),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => router?.pop(),
        ),
      ),
      Expanded(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Icon(icon, size: 80, color: Colors.grey),
              const SizedBox(height: 16),
              Text(
                title,
                style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 8),
              const Text(
                '这是一个示例页面',
                style: TextStyle(color: Colors.grey),
              ),
            ],
          ),
        ),
      ),
    ],
  );
}
1
likes
135
points
68
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Enhanced Flutter router with lifecycle awareness, launch modes, route guards, and more.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on router_pro

Packages that implement router_pro