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

Flutter中如何实现具有重叠样式的自定义Tabs?

实现重叠样式Tab的代码解决方案

问题描述

想要创建重叠式Tab(参考设计图样式),目前无法实现每个Tab的重叠效果,需要代码层面的设计帮助。

现有尝试代码

页面框架代码:

Scaffold(
  backgroundColor: cBackground,
  body:
      Padding(
    padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Container(
          decoration: BoxDecoration(
            border: Border.all(color: const Color(0xffDEDFE7), width: 1),
            borderRadius: const BorderRadius.only(
              topRight: Radius.circular(14),
              bottomLeft: Radius.circular(14),
              bottomRight: Radius.circular(14),
            ),
            color: Colors.white,
          ),
          width: 1800,
        ),
        ..._tabs,
      ],
    ),
  ),
);

单个Tab的布局代码:

Positioned(
  left: 0,
  child: TabletTab(
    onTap: () {},
    key: Key('key_here'),
    title: "Title",
    iconPath: Icons.fire,
  ),
);

解决方案代码

通过Stack布局实现Tab重叠,同时处理选中状态的层级与样式区分:

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

  @override
  State<OverlappingTabs> createState() => _OverlappingTabsState();
}

class _OverlappingTabsState extends State<OverlappingTabs> {
  int _selectedIndex = 0;
  final List<Map<String, dynamic>> _tabData = [
    {'title': '热点', 'icon': Icons.fire},
    {'title': '推荐', 'icon': Icons.star},
    {'title': '关注', 'icon': Icons.favorite},
    {'title': '视频', 'icon': Icons.play_arrow},
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xffF5F5F7),
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 内容容器
            Container(
              height: 300,
              decoration: BoxDecoration(
                border: Border.all(color: const Color(0xffDEDFE7), width: 1),
                borderRadius: const BorderRadius.only(
                  topRight: Radius.circular(14),
                  bottomLeft: Radius.circular(14),
                  bottomRight: Radius.circular(14),
                ),
                color: Colors.white,
              ),
              width: double.infinity,
              alignment: Alignment.center,
              child: Text('${_tabData[_selectedIndex]['title']}内容区域'),
            ),
            const SizedBox(height: 8),
            // 重叠Tab区域
            SizedBox(
              height: 50,
              child: Stack(
                children: List.generate(_tabData.length, (index) {
                  return Positioned(
                    left: index * 120.0,
                    child: GestureDetector(
                      onTap: () => setState(() => _selectedIndex = index),
                      child: Material(
                        elevation: _selectedIndex == index ? 4 : 0,
                        borderRadius: const BorderRadius.only(
                          topLeft: Radius.circular(14),
                          topRight: Radius.circular(14),
                        ),
                        child: Container(
                          width: 150,
                          height: 50,
                          padding: const EdgeInsets.symmetric(horizontal: 12),
                          decoration: BoxDecoration(
                            color: _selectedIndex == index ? Colors.white : const Color(0xffF5F5F7),
                            border: Border.all(color: const Color(0xffDEDFE7), width: 1),
                            borderRadius: const BorderRadius.only(
                              topLeft: Radius.circular(14),
                              topRight: Radius.circular(14),
                            ),
                          ),
                          child: Row(
                            children: [
                              Icon(_tabData[index]['icon'], size: 20),
                              const SizedBox(width: 8),
                              Text(_tabData[index]['title']),
                            ],
                          ),
                        ),
                      ),
                    ),
                  );
                }).reversed.toList(),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

关键实现要点

  • 用Stack+Positioned布局,通过left属性设置每个Tab的偏移量,控制重叠宽度(可根据实际Tab尺寸调整偏移值)
  • 维护选中索引,选中的Tab通过elevation提升层级,确保显示在最上层,同时切换背景色区分状态
  • 反转Tab列表顺序,让后续Tab默认处于下层,避免未选中时遮挡前面的Tab
  • Tab设置顶部圆角,与下方内容容器的圆角风格统一

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:32:55