Flutter之TabBar篇

总结了一下项目中用到的几种TabBar,针对不同的样式,有采用系统提供的,也有三方插件提供的,也有自定义的,效果如下(后续如果遇到新的样式,会不间断地记录更新,避免重复造轮子...)

用到的三方插件:

buttons_tabbar: ^1.3.8
flutter_easyloading: ^3.0.5

1、先看第一种系统的

代码如下:

复制代码
class CustomTabBar extends StatelessWidget {
  final TabController tabController;
  final List<String> tabs;
  final TextStyle labelStyle;
  final Color labelColor;
  final Color unselectedLabelColor;
  final TextStyle unselectedLabelStyle;
  final Color indicatorColor;
  final double indicatorWeight;
  const CustomTabBar({
    super.key,
    required this.tabController,
    required this.tabs,
    this.labelStyle = const TextStyle(
      fontSize: 16.0,
      fontWeight: FontWeight.w700,
    ),
    this.labelColor = Colors.blue,
    this.unselectedLabelColor = Colors.red,
    this.unselectedLabelStyle = const TextStyle(
      fontSize: 16.0,
      fontWeight: FontWeight.w400,
    ),
    this.indicatorColor = Colors.blue,
    this.indicatorWeight = 5.0,
  });

  @override
  Widget build(BuildContext context) {
    return TabBar(
      controller: tabController,
      tabs: tabs.map((e) => Tab(text: e)).toList(),
      isScrollable: true,
      labelPadding: const EdgeInsets.symmetric(horizontal: 16.0),
      labelStyle: labelStyle,
      labelColor: labelColor,
      unselectedLabelColor: unselectedLabelColor,
      unselectedLabelStyle: unselectedLabelStyle,
      indicatorWeight: indicatorWeight,
      indicator: DotTabIndicator(
        color: indicatorColor,
        radius: 4,
      ),
      onTap: (value) {},
      dividerColor: Colors.transparent, //去除tabBar下面的那根线的颜色
    );
  }
}

class DotTabIndicator extends Decoration {
  final Color color;
  final double radius;

  const DotTabIndicator({required this.color, required this.radius});

  @override
  BoxPainter createBoxPainter([VoidCallback? onChanged]) {
    return _DotTabIndicatorPainter(this, onChanged!);
  }
}

class _DotTabIndicatorPainter extends BoxPainter {
  final DotTabIndicator decoration;

  _DotTabIndicatorPainter(this.decoration, VoidCallback onChanged)
      : super(onChanged);

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final Rect rect = offset & configuration.size!;
    final Paint paint = Paint();
    paint.color = decoration.color;
    paint.style = PaintingStyle.fill;
    final Offset circleOffset =
        Offset(rect.center.dx, rect.bottomCenter.dy - decoration.radius);
    canvas.drawCircle(circleOffset, decoration.radius, paint);
  }
}

使用方法:

复制代码
late final TabController _tabController;
final List<String> _tabs = [
    "能源洞察",
    "用户故事",
    "智汇回答",
  ];
  final List<Widget> _tabViews = [
    Container(color: Colors.red),
    Container(color: Colors.yellow),
    Container(color: Colors.orange),
  ];
@override
  void initState() {
    super.initState();
    _tabController = TabController(
      initialIndex: 1,
      length: _tabs.length,
      vsync: this,
    );
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

Container(
            height: 200,
            child: Column(
              children: [
                CustomTabBar(
                  tabController: _tabController,
                  indicatorWeight: 1,
                  tabs: _tabs,
                ),
                const SizedBox(height: 10.0),
                Expanded(
                  child: TabBarView(
                    controller: _tabController,
                    children: _tabViews,
                  ),
                ),
              ],
            ),
          ),

第二种采用的三方插件buttons_tabbar: ^1.3.8

代码如下:

复制代码
  late final TabController _tabController;
  final List<String> _tabs = [
    "能源洞察",
    "用户故事",
    "智汇回答",
  ];
  final List<Widget> _tabViews = [
    Container(color: Colors.red),
    Container(color: Colors.yellow),
    Container(color: Colors.orange),
  ];
@override
  void initState() {
    super.initState();
    _tabController = TabController(
      initialIndex: 0,
      length: _tabs.length,
      vsync: this,
    );
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

SizedBox(
            height: 200,
            child: Column(
              children: [
                SizedBox(
                  height: 32.0,
                  child: ButtonsTabBar(
                    tabs: _tabs.map((e) => Tab(text: e)).toList(),
                    controller: _tabController,
                    backgroundColor: Colors.blue,
                    unselectedBackgroundColor: Colors.red,
                    labelStyle: const TextStyle(color: Colors.white),
                    unselectedLabelStyle: const TextStyle(color: Colors.black),
                    buttonMargin: const EdgeInsets.only(right: 35),
                    contentPadding:
                        const EdgeInsets.symmetric(horizontal: 15.0),
                    radius: 18,
                  ),
                ),
                const SizedBox(height: 10.0),
                Expanded(
                  child: TabBarView(
                    controller: _tabController,
                    children: _tabViews,
                  ),
                ),
              ],
            ),
          ),

第三种自定义

代码如下:

复制代码
class ButtonContainer extends StatelessWidget {
  final int containerIndex;
  final ValueChanged<int> onContainerSelected;
  final bool isSelected;
  final List data;
  final Color backgroundColor;
  final Color unBackgroundColor;
  final TextStyle labelStyle;
  final TextStyle unLabelStyle;
  const ButtonContainer({
    super.key,
    required this.containerIndex,
    required this.onContainerSelected,
    required this.isSelected,
    required this.data,
    this.backgroundColor = Colors.grey,
    this.unBackgroundColor = Colors.red,
    this.labelStyle = const TextStyle(
      color: Colors.black,
      fontSize: 16,
    ),
    this.unLabelStyle = const TextStyle(
      color: Colors.white,
      fontSize: 16,
    ),
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        onContainerSelected(containerIndex);
      },
      child: Container(
        padding: const EdgeInsets.all(8.0),
        margin: const EdgeInsets.all(10),
        decoration: BoxDecoration(
          color: isSelected ? backgroundColor : unBackgroundColor,
          borderRadius: BorderRadius.circular(8.0),
        ),
        child: Text(
          data[containerIndex],
          style: isSelected ? labelStyle : unLabelStyle,
        ),
      ),
    );
  }
}

使用方法:

复制代码
int selectedContainerIndex = 4; //默认选中第几个
final List<String> dataList = [
    "能源",
    "用户故事",
    "智回答",
    "能洞察",
    "用户故事",
    "智汇答",
  ];
  Wrap(
              children: List.generate(dataList.length, (index) {
                return ButtonContainer(
                  containerIndex: index,
                  onContainerSelected: (index) {
                    setState(() {
                      // 更新选中状态
                      selectedContainerIndex = index;
                    });
                    EasyLoading.showToast("Click---${dataList[index]}");
                  },
                  isSelected: index == selectedContainerIndex,
                  data: dataList,
                );
              }),
            ),
代码已经都贴出来了,大方向已经指出标明,至于根据项目需求更改其中的细枝末节就需要自行动手了,有不懂的可以在下方留言,看到会及时回复😊
相关推荐
孤鸿玉9 小时前
Fluter InteractiveViewer 与ScrollView滑动冲突问题解决
flutter
叽哥16 小时前
Flutter Riverpod上手指南
android·flutter·ios
BG1 天前
Flutter 简仿Excel表格组件介绍
flutter
zhangmeng1 天前
FlutterBoost在iOS26真机运行崩溃问题
flutter·app·swift
恋猫de小郭1 天前
对于普通程序员来说 AI 是什么?AI 究竟用的是什么?
前端·flutter·ai编程
卡尔特斯1 天前
Flutter A GlobalKey was used multipletimes inside one widget'schild list.The ...
flutter
w_y_fan2 天前
Flutter 滚动组件总结
前端·flutter
醉过才知酒浓2 天前
Flutter Getx 的页面传参
flutter
火柴就是我3 天前
flutter 之真手势冲突处理
android·flutter
Speed1233 天前
`mockito` 的核心“打桩”规则
flutter·dart