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

如何实现类似Snake Navigation Bar的Flutter自定义导航栏?

自定义导航栏实现优化方案

现有代码局限

你当前的组件仅实现了基础的导航切换功能,缺少自定义导航栏常见的视觉区分细节(如选中态高亮、过渡动画、布局规整性等),这是无法匹配目标样式的核心原因。以下是优化后的实现,覆盖主流自定义导航栏的样式需求:


优化后的CustomNavigationBar组件

class CustomNavigationBar extends StatelessWidget {
  final List<NavigationDestination> destinations;
  final int selectedIndex;
  final Function(int index) onDestinationSelected;
  final Color backgroundColor;
  final Color selectedColor;
  final Color unselectedColor;
  final double height;

  const CustomNavigationBar({
    Key? key,
    required this.destinations,
    required this.selectedIndex,
    required this.onDestinationSelected,
    this.backgroundColor = Colors.green,
    this.selectedColor = Colors.white,
    this.unselectedColor = Colors.black54,
    this.height = 65,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: height,
      color: backgroundColor,
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: List.generate(destinations.length, (index) {
          final isSelected = index == selectedIndex;
          return Expanded(
            child: GestureDetector(
              onTap: () => onDestinationSelected(index),
              child: AnimatedContainer(
                duration: const Duration(milliseconds: 250),
                padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
                decoration: isSelected
                    ? BoxDecoration(
                        color: selectedColor.withOpacity(0.2),
                        borderRadius: BorderRadius.circular(12),
                      )
                    : null,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    AnimatedScale(
                      scale: isSelected ? 1.2 : 1.0,
                      duration: const Duration(milliseconds: 250),
                      child: Icon(
                        isSelected
                            ? destinations[index].selectedIcon ?? destinations[index].icon
                            : destinations[index].icon,
                        color: isSelected ? selectedColor : unselectedColor,
                        size: 24,
                      ),
                    ),
                    const SizedBox(height: 4),
                    if (destinations[index].label != null)
                      AnimatedDefaultTextStyle(
                        style: TextStyle(
                          color: isSelected ? selectedColor : unselectedColor,
                          fontSize: isSelected ? 12 : 11,
                          fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
                        ),
                        duration: const Duration(milliseconds: 250),
                        child: Text(destinations[index].label!),
                      ),
                  ],
                ),
              ),
            ),
          );
        }),
      ),
    );
  }
}

核心优化点

  • 可配置参数:支持自定义背景色、选中/未选中颜色、导航栏高度,适配不同UI需求
  • 选中态高亮:给选中项添加半透明背景圆角,强化视觉区分
  • 过渡动画:图标缩放、文字样式平滑过渡,提升交互体验
  • 规整布局:用Expanded让每个导航项平分宽度,避免布局错乱
  • 图标差异化:支持selectedIcon属性,选中时可切换为填充图标

使用示例

// 定义带选中态图标的导航项
final List<NavigationDestination> destinations = [
  NavigationDestination(
    icon: Icons.home_outlined,
    selectedIcon: Icons.home,
    label: '首页',
  ),
  NavigationDestination(
    icon: Icons.search_outlined,
    selectedIcon: Icons.search,
    label: '搜索',
  ),
  NavigationDestination(
    icon: Icons.shopping_cart_outlined,
    selectedIcon: Icons.shopping_cart,
    label: '购物车',
  ),
];

// 在页面中集成
CustomNavigationBar(
  destinations: destinations,
  selectedIndex: _selectedIndex,
  onDestinationSelected: (index) {
    setState(() {
      _selectedIndex = index;
    });
  },
  backgroundColor: Colors.green.shade700,
  selectedColor: Colors.white,
  unselectedColor: Colors.white70,
)

针对特殊样式的扩展

如果你的目标样式有特殊需求,可针对性修改:

  • 底部指示器:在选中项的Column末尾添加:
    if (isSelected)
      Container(
        height: 2,
        width: 24,
        color: selectedColor,
        margin: const EdgeInsets.only(top: 4),
      ),
    
  • 凸起胶囊选中态:修改AnimatedContainer的decoration:
    decoration: isSelected
        ? BoxDecoration(
            color: selectedColor,
            borderRadius: BorderRadius.circular(20),
            boxShadow: [
              BoxShadow(
                color: Colors.black12,
                blurRadius: 8,
                offset: const Offset(0, -2),
              ),
            ],
          )
        : null,
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:03:18