You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter底部导航栏(Bottom Navigation Bar)最优实现方式咨询

最优实现Flutter底部导航栏方案

核心思路

基于Flutter原生BottomNavigationBar配合IndexedStack管理页面状态,既能利用原生组件的跨平台兼容性,又能高效保持页面状态,同时支持自定义中间凸起按钮这类特殊样式,是兼顾性能与扩展性的最优方案。

完整代码实现

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Bottom Nav Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const BottomNavScreen(),
    );
  }
}

class BottomNavScreen extends StatefulWidget {
  const BottomNavScreen({super.key});

  @override
  State<BottomNavScreen> createState() => _BottomNavScreenState();
}

class _BottomNavScreenState extends State<BottomNavScreen> {
  int _currentIndex = 0;

  // 导航项配置
  final List<BottomNavigationBarItem> _navItems = const [
    BottomNavigationBarItem(
      icon: Icon(Icons.home_outlined),
      activeIcon: Icon(Icons.home),
      label: '首页',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.search_outlined),
      activeIcon: Icon(Icons.search),
      label: '搜索',
    ),
    BottomNavigationBarItem(icon: SizedBox(), label: ''), // 占位项
    BottomNavigationBarItem(
      icon: Icon(Icons.favorite_outlined),
      activeIcon: Icon(Icons.favorite),
      label: '收藏',
    ),
    BottomNavigationBarItem(
      icon: Icon(Icons.person_outlined),
      activeIcon: Icon(Icons.person),
      label: '我的',
    ),
  ];

  // 页面列表,用IndexedStack保持状态
  final List<Widget> _pages = const [
    HomePage(),
    SearchPage(),
    SizedBox(), // 对应占位项的空页面
    FavoritePage(),
    ProfilePage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: _currentIndex,
        children: _pages,
      ),
      bottomNavigationBar: Stack(
        children: [
          BottomNavigationBar(
            currentIndex: _currentIndex,
            type: BottomNavigationBarType.fixed,
            items: _navItems,
            onTap: (index) {
              if (index == 2) return; // 跳过占位项
              setState(() => _currentIndex = index);
            },
            selectedItemColor: Colors.blue,
            unselectedItemColor: Colors.grey,
            elevation: 8,
          ),
          // 中间凸起的自定义操作按钮
          Positioned(
            left: MediaQuery.of(context).size.width / 2 - 35,
            bottom: 10,
            child: GestureDetector(
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (_) => const PublishPage()));
              },
              child: Container(
                width: 70,
                height: 70,
                decoration: const BoxDecoration(
                  color: Colors.blue,
                  shape: BoxShape.circle,
                  boxShadow: [BoxShadow(blurRadius: 6, color: Colors.black26)],
                ),
                child: const Icon(Icons.add, color: Colors.white, size: 32),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// 示例页面组件
class HomePage extends StatelessWidget {
  const HomePage({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('首页'));
}

class SearchPage extends StatelessWidget {
  const SearchPage({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('搜索'));
}

class FavoritePage extends StatelessWidget {
  const FavoritePage({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('收藏'));
}

class ProfilePage extends StatelessWidget {
  const ProfilePage({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('我的'));
}

class PublishPage extends StatelessWidget {
  const PublishPage({super.key});
  @override
  Widget build(BuildContext context) => Scaffold(appBar: AppBar(title: const Text('发布')), body: const Center(child: Text('发布页面')));
}

方案优势

  • 原生适配:基于官方组件,自动匹配iOS/Android平台的默认样式,无需额外适配
  • 状态持久:IndexedStack会保留所有页面的状态,切换时不会重新初始化组件,提升性能
  • 灵活定制:通过Stack叠加自定义按钮,可自由修改按钮的大小、颜色、阴影等样式,满足个性化需求
  • 易维护:导航项和页面列表采用数组配置,增减页面只需修改对应数组,逻辑清晰

注意事项

  • 若无需中间凸起按钮,直接移除Stack中的Positioned组件,并删除占位的导航项即可
  • 如需更复杂的子页面路由管理,可给每个页面绑定GlobalKey<NavigatorState>,实现独立的页面栈
  • 自定义按钮的位置通过屏幕宽度计算,确保在不同尺寸设备上居中显示

内容的提问来源于stack exchange,提问作者Fadi Ft Ftena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:25:18