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

Flutter中如何实现自定义底部导航栏

Flutter 自定义凸起底部导航栏实现教程

自定义底部导航栏效果参考图

实现思路

这种中间凸起的底部导航栏不用引入第三方库,用Flutter自带组件即可实现,核心逻辑是:

  • 用 Scaffold 自带的 floatingActionButton 属性实现中间凸起按钮
  • 搭配 floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked 让按钮嵌入底部导航栏中间位置
  • 底部导航栏用 BottomAppBar 配合 Row 排列左右两侧的导航项
  • 用 IndexedStack 或者 PageView 管理导航对应的页面切换,保留页面状态

完整可运行示例代码

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: '自定义底部导航',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomePage(),
    );
  }
}

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

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

class _HomePageState extends State<HomePage> {
  // 当前选中的导航索引
  int _currentIndex = 0;

  // 导航对应的页面列表
  final List<Widget> _pages = const [
    HomeScreen(),
    CategoryScreen(),
    PublishScreen(),
    CartScreen(),
    MineScreen(),
  ];

  // 导航项配置
  final List<Map<String, dynamic>> _navItems = [
    {'icon': Icons.home, 'label': '首页'},
    {'icon': Icons.category, 'label': '分类'},
    {'icon': null, 'label': '发布'}, // 中间凸起按钮单独处理
    {'icon': Icons.shopping_cart, 'label': '购物车'},
    {'icon': Icons.person, 'label': '我的'},
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: _currentIndex,
        children: _pages,
      ),
      // 底部导航栏
      bottomNavigationBar: BottomAppBar(
        shape: const CircularNotchedRectangle(), // 中间凹口适配凸起按钮
        notchMargin: 6, // 凹口和按钮的间距
        child: Container(
          height: 60,
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: List.generate(_navItems.length, (index) {
              // 中间位置留空给FloatingActionButton
              if (index == 2) {
                return const SizedBox(width: 40);
              }
              return GestureDetector(
                onTap: () {
                  setState(() {
                    _currentIndex = index;
                  });
                },
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Icon(
                      _navItems[index]['icon'],
                      color: _currentIndex == index ? Colors.blue : Colors.grey,
                      size: 24,
                    ),
                    Text(
                      _navItems[index]['label'],
                      style: TextStyle(
                        color: _currentIndex == index ? Colors.blue : Colors.grey,
                        fontSize: 12,
                      ),
                    )
                  ],
                ),
              );
            }),
          ),
        ),
      ),
      // 中间凸起按钮
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.blue,
        shape: const CircleBorder(),
        onPressed: () {
          setState(() {
            _currentIndex = 2;
          });
          // 如果不需要跳转到页面,这里直接写你要的逻辑,比如弹出发布窗口
        },
        child: const Icon(Icons.add, color: Colors.white, size: 30),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }
}

// 示例页面,你可以替换成自己的页面实现
class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('首页'));
}
class CategoryScreen extends StatelessWidget {
  const CategoryScreen({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('分类'));
}
class PublishScreen extends StatelessWidget {
  const PublishScreen({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('发布页'));
}
class CartScreen extends StatelessWidget {
  const CartScreen({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('购物车'));
}
class MineScreen extends StatelessWidget {
  const MineScreen({super.key});
  @override
  Widget build(BuildContext context) => const Center(child: Text('我的'));
}

自定义调整说明

  • 可以修改 BottomAppBar 的 color 属性调整导航栏背景色,修改 shape 调整凹口样式
  • 可以修改 FloatingActionButton 的样式、图标、点击逻辑适配你的业务需求
  • 如果需要页面切换动画,把 IndexedStack 替换为 PageView + PageController 即可
  • 导航项的图标、文字、选中色都可以根据你的设计稿调整

内容的提问来源于stack exchange,提问作者Shammah

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 08:12:04