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

Flutter中能否实现自定义样式的文本下划线?

在Flutter中实现自定义样式下划线

完全可以实现这类自定义下划线,Flutter的自定义绘制能力能满足这类需求,下面提供两种实用方案:

方案一:使用CustomPaint自定义绘制

通过自定义CustomPainter,可以精准控制下划线的样式、位置和文本排版:

class CustomUnderlineText extends StatelessWidget {
  final String text;
  final TextStyle style;
  final Color underlineColor1;
  final Color underlineColor2;
  final double underlineThickness1;
  final double underlineThickness2;
  final double underlineGap;

  const CustomUnderlineText({
    super.key,
    required this.text,
    required this.style,
    this.underlineColor1 = Colors.black,
    this.underlineColor2 = Colors.grey,
    this.underlineThickness1 = 3,
    this.underlineThickness2 = 1,
    this.underlineGap = 2,
  });

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: _CustomUnderlinePainter(
        text: text,
        style: style,
        underlineColor1: underlineColor1,
        underlineColor2: underlineColor2,
        underlineThickness1: underlineThickness1,
        underlineThickness2: underlineThickness2,
        underlineGap: underlineGap,
      ),
      child: Text(text, style: style),
    );
  }
}

class _CustomUnderlinePainter extends CustomPainter {
  final String text;
  final TextStyle style;
  final Color underlineColor1;
  final Color underlineColor2;
  final double underlineThickness1;
  final double underlineThickness2;
  final double underlineGap;

  _CustomUnderlinePainter({
    required this.text,
    required this.style,
    required this.underlineColor1,
    required this.underlineColor2,
    required this.underlineThickness1,
    required this.underlineThickness2,
    required this.underlineGap,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // 计算文本宽度与基线位置
    final textPainter = TextPainter(
      text: TextSpan(text: text, style: style),
      textDirection: TextDirection.ltr,
    )..layout(minWidth: 0, maxWidth: size.width);

    final lineMetrics = textPainter.computeLineMetrics().first;
    final textBottom = lineMetrics.baseline + lineMetrics.descent;

    // 绘制第一条下划线(粗线)
    final paint1 = Paint()
      ..color = underlineColor1
      ..style = PaintingStyle.fill;
    canvas.drawRect(
      Rect.fromLTWH(
        0,
        textBottom + underlineGap,
        textPainter.width,
        underlineThickness1,
      ),
      paint1,
    );

    // 绘制第二条下划线(细线)
    final paint2 = Paint()
      ..color = underlineColor2
      ..style = PaintingStyle.fill;
    canvas.drawRect(
      Rect.fromLTWH(
        0,
        textBottom + underlineGap * 2 + underlineThickness1,
        textPainter.width,
        underlineThickness2,
      ),
      paint2,
    );
  }

  @override
  bool shouldRepaint(covariant _CustomUnderlinePainter oldDelegate) {
    return text != oldDelegate.text ||
        style != oldDelegate.style ||
        underlineColor1 != oldDelegate.underlineColor1 ||
        underlineColor2 != oldDelegate.underlineColor2 ||
        underlineThickness1 != oldDelegate.underlineThickness1 ||
        underlineThickness2 != oldDelegate.underlineThickness2 ||
        underlineGap != oldDelegate.underlineGap;
  }
}

使用方式:

CustomUnderlineText(
  text: "自定义下划线示例",
  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
  underlineColor1: Colors.blue,
  underlineColor2: Colors.lightBlue,
)

方案二:使用Stack组合文本与自定义线条

如果觉得自定义绘制太复杂,也可以用Stack将文本和两条Container线条组合,通过定位实现效果:

Widget customUnderlineText(String text) {
  return LayoutBuilder(
    builder: (context, constraints) {
      // 先获取文本实际宽度
      final textPainter = TextPainter(
        text: TextSpan(text: text, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
        textDirection: TextDirection.ltr,
      )..layout(maxWidth: constraints.maxWidth);
      
      return Stack(
        alignment: Alignment.bottomLeft,
        children: [
          Text(
            text,
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          Positioned(
            bottom: -8,
            child: Column(
              children: [
                Container(
                  width: textPainter.width,
                  height: 3,
                  color: Colors.blue,
                ),
                SizedBox(height: 2),
                Container(
                  width: textPainter.width,
                  height: 1,
                  color: Colors.lightBlue,
                ),
              ],
            ),
          ),
        ],
      );
    },
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:55:23