Flutter中点击自定义底部导航栏如何实现页面切换
Flutter自定义底部导航栏页面切换实现方案
你已完成底部导航栏的UI交互与选中状态逻辑,补充页面映射与容器结构即可实现切换功能,完整修改代码如下:
import 'package:flutter/material.dart'; // 示例首页,可替换为你的实际页面内容 class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { return Container( color: Colors.white, child: const Center(child: Text("首页", style: TextStyle(fontSize: 24))), ); } } // 示例搜索页,可替换为你的实际页面内容 class SearchPage extends StatelessWidget { const SearchPage({super.key}); @override Widget build(BuildContext context) { return Container( color: Colors.white, child: const Center(child: Text("搜索", style: TextStyle(fontSize: 24))), ); } } // 示例我的账户页,可替换为你的实际页面内容 class AccountPage extends StatelessWidget { const AccountPage({super.key}); @override Widget build(BuildContext context) { return Container( color: Colors.white, child: const Center(child: Text("我的账户", style: TextStyle(fontSize: 24))), ); } } class NavBarController extends StatefulWidget { const NavBarController({Key? key}) : super(key: key); @override _NavBarControllerState createState() => _NavBarControllerState(); } class _NavBarControllerState extends State<NavBarController> { int selectedIndex = 0; Color backgroundColor = Colors.white; // 页面列表,顺序和下方导航项顺序一一对应 final List<Widget> pageList = const [ HomePage(), SearchPage(), AccountPage(), ]; List<NavigationItem> items = [ NavigationItem(const Icon(Icons.home), const Text('首页'), Colors.blue), NavigationItem(const Icon(Icons.search), const Text('搜索'), Colors.blue), NavigationItem(const Icon(Icons.people), const Text('我的账户'), Colors.blue) ]; Widget _buildItem(NavigationItem item, bool isSelected) { return AnimatedContainer( duration: const Duration(milliseconds: 200), height: double.maxFinite, width: isSelected ? 165 : 70, padding: const EdgeInsets.only(left: 20, right: 10), decoration: BoxDecoration( color: isSelected ? item.color : Colors.white, borderRadius: const BorderRadius.all(Radius.circular(50))), child: ListView( scrollDirection: Axis.horizontal, children: <Widget>[ Row( crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ IconTheme( data: IconThemeData( size: 24, color: isSelected ? backgroundColor : Colors.grey, ), child: item.icon, ), Padding( padding: const EdgeInsets.only(left: 8), child: isSelected ? DefaultTextStyle.merge( style: TextStyle(color: backgroundColor), child: item.title, ) : Container(), ) ], ) ], ), ); } @override Widget build(BuildContext context) { return Scaffold( // 页面主体,使用IndexedStack保留页面切换状态 body: IndexedStack( index: selectedIndex, children: pageList, ), // 自定义悬浮导航栏 bottomNavigationBar: Container( height: 65, width: double.infinity, margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20), padding: const EdgeInsets.only(left: 8, top: 8, right: 8, bottom: 8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(50), color: backgroundColor, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.4), spreadRadius: 0.5, blurRadius: 10, offset: const Offset(0, 5), ) ]), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: items.map((item) { var itemIndex = items.indexOf(item); return GestureDetector( onTap: () { setState(() { selectedIndex = itemIndex; }); }, child: _buildItem(item, selectedIndex == itemIndex), ); }).toList(), ), ), ); } } class NavigationItem { final Icon icon; final Text title; final Color color; NavigationItem(this.icon, this.title, this.color); }
主要修改说明
- 新增了3个示例页面,你可以直接替换为自己的业务页面代码
- 新增
pageList列表存储页面对象,顺序和导航项保持一致即可自动对应 - 采用
IndexedStack承载页面,切换时会保留各页面的原有状态,不需要每次重建 - 调整了布局结构,将自定义导航栏放入
Scaffold的bottomNavigationBar属性,适配悬浮导航的展示效果
内容的提问来源于stack exchange,提问作者Saw Tha Wah
相关产品推荐
相关产品推荐

