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

Flutter中如何制作带间距的按钮式Tab Bars?匹配图示样式

Flutter实现两类自定义Tab Bar效果

一、带间距的按钮式Tab Bar

这种Tab Bar将每个选项做成独立按钮样式,选项间保留明显间距,适合突出单个Tab按钮的场景。

实现代码

import 'package:flutter/material.dart';

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

  @override
  State<SpacedButtonTabBar> createState() => _SpacedButtonTabBarState();
}

class _SpacedButtonTabBarState extends State<SpacedButtonTabBar> with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("带间距的按钮Tab Bar"),
        bottom: TabBar(
          controller: _tabController,
          // 控制Tab之间的横向间距
          labelPadding: const EdgeInsets.symmetric(horizontal: 16),
          // 自定义选中状态的按钮背景
          indicator: BoxDecoration(
            color: Colors.blue.shade50,
            borderRadius: BorderRadius.circular(8),
          ),
          labelColor: Colors.blue,
          unselectedLabelColor: Colors.grey,
          // 自定义Tab内边距,形成按钮形态
          tabs: const [
            Tab(
              child: Padding(
                padding: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
                child: Text("首页"),
              ),
            ),
            Tab(
              child: Padding(
                padding: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
                child: Text("分类"),
              ),
            ),
            Tab(
              child: Padding(
                padding: EdgeInsets.symmetric(vertical: 8, horizontal: 20),
                child: Text("我的"),
              ),
            ),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: const [
          Center(child: Text("首页内容区域")),
          Center(child: Text("分类内容区域")),
          Center(child: Text("我的内容区域")),
        ],
      ),
    );
  }
}

关键实现点

  • 通过labelPadding设置Tab之间的横向间距,避免选项拥挤
  • 给Tab内部添加Padding,让每个Tab呈现按钮尺寸
  • 用BoxDecoration作为indicator,实现选中时的按钮背景高亮效果

二、匹配示例样式的Tab Bar

示例样式核心特征:底部带自适应宽度的下划线指示器,选中时下划线加粗变色,Tab文字同步切换粗细与颜色。

实现代码

import 'package:flutter/material.dart';

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

  @override
  State<SampleStyledTabBar> createState() => _SampleStyledTabBarState();
}

class _SampleStyledTabBarState extends State<SampleStyledTabBar> with SingleTickerProviderStateMixin {
  late TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 4, vsync: this);
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("示例样式Tab Bar"),
        bottom: TabBar(
          controller: _tabController,
          labelColor: Colors.blue,
          unselectedLabelColor: Colors.grey.shade600,
          // 自定义下划线指示器,控制宽度与高度
          indicator: const UnderlineTabIndicator(
            borderSide: BorderSide(width: 3, color: Colors.blue),
            // 通过insets控制下划线左右缩进,适配文字宽度
            insets: EdgeInsets.symmetric(horizontal: 18),
          ),
          labelStyle: const TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w600,
          ),
          unselectedLabelStyle: const TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.normal,
          ),
          tabs: const [
            Tab(text: "推荐"),
            Tab(text: "热门"),
            Tab(text: "关注"),
            Tab(text: "最新"),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: const [
          Center(child: Text("推荐内容")),
          Center(child: Text("热门内容")),
          Center(child: Text("关注内容")),
          Center(child: Text("最新内容")),
        ],
      ),
    );
  }
}

进阶自定义(精准匹配文字宽度)

如果需要下划线宽度完全贴合文字,可以自定义指示器:

class CustomTextUnderlineIndicator extends Decoration {
  final double height;
  final Color color;

  const CustomTextUnderlineIndicator({
    required this.height,
    required this.color,
  });

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

class _CustomIndicatorPainter extends BoxPainter {
  final CustomTextUnderlineIndicator decoration;

  _CustomIndicatorPainter(this.decoration, VoidCallback? onChanged) : super(onChanged);

  @override
  void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
    final textPainter = TextPainter(
      text: TextSpan(
        text: configuration.text ?? "",
        style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
      ),
      textDirection: TextDirection.ltr,
    )..layout();

    final textWidth = textPainter.width;
    final centerX = offset.dx + configuration.size!.width / 2;
    final left = centerX - textWidth / 2;
    final right = centerX + textWidth / 2;

    final paint = Paint()
      ..color = decoration.color
      ..style = PaintingStyle.fill;

    canvas.drawRRect(
      RRect.fromRectAndRadius(
        Rect.fromLTWH(left, configuration.size!.height - decoration.height, right - left, decoration.height),
        Radius.circular(decoration.height / 2),
      ),
      paint,
    );
  }
}

使用时替换TabBar的indicator:

indicator: const CustomTextUnderlineIndicator(
  height: 3,
  color: Colors.blue,
),

内容的提问来源于stack exchange,提问作者Mr.Robot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 23:15:35