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,
                );
              }),
            ),
代码已经都贴出来了,大方向已经指出标明,至于根据项目需求更改其中的细枝末节就需要自行动手了,有不懂的可以在下方留言,看到会及时回复😊
相关推荐
problc9 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
lqj_本人17 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos
lqj_本人20 小时前
Flutter&鸿蒙next 状态管理框架对比分析
flutter·华为·harmonyos
起司锅仔1 天前
Flutter启动流程(2)
flutter
hello world smile1 天前
最全的Flutter中pubspec.yaml及其yaml 语法的使用说明
android·前端·javascript·flutter·dart·yaml·pubspec.yaml
lqj_本人1 天前
Flutter 的 Widget 概述与常用 Widgets 与鸿蒙 Next 的对比
flutter·harmonyos
iFlyCai1 天前
极简实现酷炫动效:Flutter隐式动画指南第二篇之一些酷炫的隐式动画效果
flutter
lqj_本人1 天前
Flutter&鸿蒙next 中使用 MobX 进行状态管理
flutter·华为·harmonyos
lqj_本人1 天前
Flutter&鸿蒙next 中的 setState 使用场景与最佳实践
flutter·华为·harmonyos
hello world smile1 天前
Flutter常用命令整理
android·flutter·移动开发·android studio·安卓