现在位置: 首页 > Flutter 教程 > 正文

Flutter 导航与路由

本节将介绍 Flutter 中的导航和路由机制,包括页面跳转、参数传递和命名路由。


Navigator 基础

Flutter 使用 Navigator 进行页面管理,基于栈(stack)结构实现页面跳转。

实例:基本页面跳转

// 跳转到新页面
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

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

// 带结果返回
Navigator.of(context).pop('返回的数据');

// 替换当前页面(不可返回)
Navigator.of(context).pushReplacement(
  MaterialPageRoute(
    builder: (context) => const HomePage(),
  ),
);

// 回到根页面
Navigator.of(context).popUntil((route) => route.isFirst);

MaterialPageRoute vs CupertinoPageRoute

实例:不同平台的页面切换动画

// Android 风格 - 从底部升起
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// iOS 风格 - 从右侧滑入
Navigator.of(context).push(
  CupertinoPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// 自定义过渡效果
Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) {
      return const DetailPage();
    },
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      // 淡入淡出效果
      return FadeTransition(
        opacity: animation,
        child: child,
      );
    },
    transitionDuration: const Duration(milliseconds: 300),
  ),
);

页面参数传递

< h2 class="example">实例:传递参数到新页面
// 跳转到详情页并传递参数
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ProductDetailPage(productId: 123),
  ),
);

// 详情页接收参数
class ProductDetailPage extends StatelessWidget {
  final int productId;

  const ProductDetailPage({
    super.key,
    required this.productId,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('商品 $productId')),
      body: Center(child: Text('商品 ID: $productId')),
    );
  }
}

// 传递多个参数
class UserProfilePage extends StatelessWidget {
  final String name;
  final int age;

  const UserProfilePage({
    super.key,
    required this.name,
    required this.age,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('$name 的主页')),
      body: Center(child: Text('年龄: $age')),
    );
  }
}

// 跳转
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const UserProfilePage(
      name: '张三',
      age: 25,
    ),
  ),
);

命名路由

使用命名路由可以简化页面跳转配置。

实例:命名路由配置

void main() {
  runApp(
    MaterialApp(
      // 定义路由表
      initialRoute: '/',
      routes: {
        '/': (context) => const HomePage(),
        '/detail': (context) => const DetailPage(),
        '/user': (context) => const UserPage(),
        '/settings': (context) => const SettingsPage(),
      },
    ),
  );
}

// 跳转
Navigator.pushNamed(context, '/detail');

// 带参数跳转
Navigator.pushNamed(context, '/user', arguments: {'name': '张三', 'age': 25});

// 在目标页面获取参数
class DetailPage extends StatelessWidget {
  const DetailPage({super.key});

  @override
  Widget build(BuildContext context) {
    // 获取传递的参数
    final args = ModalRoute.of(context)?.settings.arguments as Map?;

    return Scaffold(
      appBar: AppBar(title: const Text('详情页')),
      body: Center(
        child: Text('参数: $args'),
      ),
    );
  }
}

路由传值的另一种方式

实例:onGenerateRoute

MaterialApp(
  onGenerateRoute: (settings) {
    // 根据路由名称返回不同页面
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (_) => const HomePage(),
        );
      case '/detail':
        // 从 arguments 获取参数
        final args = settings.arguments as Map<String, dynamic>?;
        return MaterialPageRoute(
          builder: (_) => DetailPage(
            id: args?['id'] ?? 0,
            title: args?['title'] ?? '',
          ),
        );
      case '/product':
        final productId = settings.name?.split('/').last;
        return MaterialPageRoute(
          builder: (_) => ProductPage(id: productId ?? ''),
        );
      default:
        return MaterialPageRoute(
          builder: (_) => const NotFoundPage(),
        );
    }
  },
)

对于简单的应用,基础 Navigator.push 就足够了;对于中大型应用,建议使用命名路由或路由管理库来统一管理页面。