<返回目录     Powered by claud/xia兄

第7课: 路由导航

Navigator、路由传参、命名路由

基本路由导航

1. 跳转到新页面

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

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

2. 完整示例

// 首页
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('首页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => DetailPage()),
            );
          },
          child: Text('跳转到详情页'),
        ),
      ),
    );
  }
}

// 详情页
class DetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('详情页')),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('返回'),
        ),
      ),
    );
  }
}

路由传参

1. 传递参数到新页面

// 传递参数
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => DetailPage(
      id: 123,
      title: '商品详情',
    ),
  ),
);

// 接收参数
class DetailPage extends StatelessWidget {
  final int id;
  final String title;

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

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

2. 返回数据到上一页

// 页面A:等待返回结果
class PageA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('页面A')),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            final result = await Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => PageB()),
            );
            print('返回的结果: $result');
          },
          child: Text('跳转到页面B'),
        ),
      ),
    );
  }
}

// 页面B:返回数据
class PageB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('页面B')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context, '选择了选项1');
              },
              child: Text('选项1'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context, '选择了选项2');
              },
              child: Text('选项2'),
            ),
          ],
        ),
      ),
    );
  }
}

命名路由

1. 配置路由表

// main.dart
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter路由示例',
      initialRoute: '/',  // 初始路由
      routes: {
        '/': (context) => HomePage(),
        '/detail': (context) => DetailPage(),
        '/settings': (context) => SettingsPage(),
        '/profile': (context) => ProfilePage(),
      },
    );
  }
}

2. 使用命名路由导航

// 跳转到命名路由
Navigator.pushNamed(context, '/detail');

// 替换当前路由
Navigator.pushReplacementNamed(context, '/home');

// 清空路由栈并跳转
Navigator.pushNamedAndRemoveUntil(
  context,
  '/home',
  (route) => false,  // 移除所有路由
);

3. 命名路由传参

// 传递参数
Navigator.pushNamed(
  context,
  '/detail',
  arguments: {
    'id': 123,
    'title': '商品详情',
  },
);

// 接收参数
class DetailPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final args = ModalRoute.of(context)!.settings.arguments as Map;
    final id = args['id'];
    final title = args['title'];

    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(child: Text('ID: $id')),
    );
  }
}

路由生成器

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter路由',
      onGenerateRoute: (settings) {
        // 根据路由名称返回对应页面
        if (settings.name == '/detail') {
          final args = settings.arguments as Map;
          return MaterialPageRoute(
            builder: (context) => DetailPage(
              id: args['id'],
              title: args['title'],
            ),
          );
        }
        // 未知路由
        return MaterialPageRoute(
          builder: (context) => NotFoundPage(),
        );
      },
    );
  }
}

路由动画

// 自定义路由动画
Navigator.push(
  context,
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => DetailPage(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      // 滑动动画
      const begin = Offset(1.0, 0.0);
      const end = Offset.zero;
      const curve = Curves.easeInOut;
      var tween = Tween(begin: begin, end: end).chain(
        CurveTween(curve: curve),
      );
      return SlideTransition(
        position: animation.drive(tween),
        child: child,
      );
    },
    transitionDuration: Duration(milliseconds: 300),
  ),
);

// 淡入动画
Navigator.push(
  context,
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => DetailPage(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      return FadeTransition(
        opacity: animation,
        child: child,
      );
    },
  ),
);

// 缩放动画
Navigator.push(
  context,
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) => DetailPage(),
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      return ScaleTransition(
        scale: animation,
        child: child,
      );
    },
  ),
);

底部导航栏

class MainPage extends StatefulWidget {
  @override
  State createState() => _MainPageState();
}

class _MainPageState extends State {
  int _currentIndex = 0;

  final List _pages = [
    HomePage(),
    CategoryPage(),
    CartPage(),
    ProfilePage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        type: BottomNavigationBarType.fixed,
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: '首页',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: '分类',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.shopping_cart),
            label: '购物车',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.person),
            label: '我的',
          ),
        ],
      ),
    );
  }
}

TabBar导航

class TabBarPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 3,
      child: Scaffold(
        appBar: AppBar(
          title: Text('TabBar示例'),
          bottom: TabBar(
            tabs: [
              Tab(icon: Icon(Icons.home), text: '首页'),
              Tab(icon: Icon(Icons.star), text: '收藏'),
              Tab(icon: Icon(Icons.person), text: '我的'),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            Center(child: Text('首页内容')),
            Center(child: Text('收藏内容')),
            Center(child: Text('我的内容')),
          ],
        ),
      ),
    );
  }
}

Drawer抽屉导航

Scaffold(
  appBar: AppBar(title: Text('抽屉导航')),
  drawer: Drawer(
    child: ListView(
      padding: EdgeInsets.zero,
      children: [
        DrawerHeader(
          decoration: BoxDecoration(
            color: Colors.blue,
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              CircleAvatar(
                radius: 30,
                backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
              ),
              SizedBox(height: 10),
              Text(
                '用户名',
                style: TextStyle(color: Colors.white, fontSize: 18),
              ),
            ],
          ),
        ),
        ListTile(
          leading: Icon(Icons.home),
          title: Text('首页'),
          onTap: () {
            Navigator.pop(context);
            Navigator.pushNamed(context, '/home');
          },
        ),
        ListTile(
          leading: Icon(Icons.settings),
          title: Text('设置'),
          onTap: () {
            Navigator.pop(context);
            Navigator.pushNamed(context, '/settings');
          },
        ),
        Divider(),
        ListTile(
          leading: Icon(Icons.exit_to_app),
          title: Text('退出'),
          onTap: () {
            // 退出逻辑
          },
        ),
      ],
    ),
  ),
  body: Center(child: Text('主页内容')),
)
路由最佳实践

练习任务

  1. 创建一个三页应用,实现页面间的跳转和返回
  2. 实现一个商品列表页,点击跳转到详情页并传递商品信息
  3. 创建一个带底部导航栏的应用,包含4个Tab页
  4. 实现一个登录页面,登录成功后跳转到主页并清空路由栈
  5. 创建一个带侧边抽屉的应用,实现菜单导航