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

Flutter TextField如何实现文本带圆角的彩色背景效果

要实现自定义绘制的带padding、圆角、无行间隙的TextField文本背景效果,可通过自定义绘制层+实时计算文本行边界的方案完成,具体实现如下:

核心逻辑

  1. 通过TextPainter布局输入文本,计算每一行文本的精确坐标和尺寸
  2. 对每行文本的边界做padding拓展,根据相邻行的位置关系自动合并圆角,消除行间隙
  3. 把自定义背景绘制层放在TextField下层,文本变化时实时重绘背景即可

完整实现代码

自定义背景绘制类

class HighlightBackgroundPainter extends CustomPainter {
  final String text;
  final TextStyle textStyle;
  final double paddingHorizontal;
  final double paddingVertical;
  final double borderRadius;
  final Color bgColor;
  final TextDirection textDirection;

  HighlightBackgroundPainter({
    required this.text,
    required this.textStyle,
    required this.paddingHorizontal,
    required this.paddingVertical,
    required this.borderRadius,
    required this.bgColor,
    required this.textDirection,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final textPainter = TextPainter(
      text: TextSpan(text: text, style: textStyle),
      textDirection: textDirection,
      maxLines: null,
    );
    textPainter.layout(maxWidth: size.width);

    final bgPaint = Paint()..color = bgColor;
    List<Rect> lineRects = [];
    final lineMetrics = textPainter.computeLineMetrics();

    // 计算每行文本拓展padding后的边界
    for (var line in lineMetrics) {
      lineRects.add(Rect.fromLTWH(
        line.left - paddingHorizontal,
        line.baseline - line.ascent - paddingVertical,
        line.width + paddingHorizontal * 2,
        line.height + paddingVertical * 2,
      ));
    }

    // 绘制带圆角的背景,处理相邻行的圆角合并
    for (int i = 0; i < lineRects.length; i++) {
      final rect = lineRects[i];
      bool hasPrevOverlap = i > 0 && (lineRects[i-1].right > rect.left && lineRects[i-1].left < rect.right);
      bool hasNextOverlap = i < lineRects.length -1 && (lineRects[i+1].right > rect.left && lineRects[i+1].left < rect.right);

      final rrect = RRect.fromRectAndCorners(
        rect,
        topLeft: hasPrevOverlap ? Radius.zero : Radius.circular(borderRadius),
        topRight: hasPrevOverlap ? Radius.zero : Radius.circular(borderRadius),
        bottomLeft: hasNextOverlap ? Radius.zero : Radius.circular(borderRadius),
        bottomRight: hasNextOverlap ? Radius.zero : Radius.circular(borderRadius),
      );
      canvas.drawRRect(rrect, bgPaint);
    }
  }

  @override
  bool shouldRepaint(covariant HighlightBackgroundPainter oldDelegate) {
    return oldDelegate.text != text ||
        oldDelegate.textStyle != textStyle ||
        oldDelegate.paddingHorizontal != paddingHorizontal ||
        oldDelegate.paddingVertical != paddingVertical ||
        oldDelegate.borderRadius != borderRadius ||
        oldDelegate.bgColor != bgColor ||
        oldDelegate.textDirection != textDirection;
  }
}

封装带高亮背景的TextField

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

  @override
  State<HighlightTextField> createState() => _HighlightTextFieldState();
}

class _HighlightTextFieldState extends State<HighlightTextField> {
  final TextEditingController _controller = TextEditingController(text: "输入测试文本\n多行换行效果测试");
  final TextStyle textStyle = const TextStyle(fontSize: 16, color: Colors.white, height: 1.2);

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // 背景绘制层
        Positioned.fill(
          child: CustomPaint(
            painter: HighlightBackgroundPainter(
              text: _controller.text,
              textStyle: textStyle,
              paddingHorizontal: 8,
              paddingVertical: 4,
              borderRadius: 6,
              bgColor: Colors.blue,
              textDirection: Directionality.of(context),
            ),
          ),
        ),
        // 文本输入层
        TextField(
          controller: _controller,
          style: textStyle,
          maxLines: null,
          decoration: const InputDecoration(
            border: InputBorder.none,
            contentPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
          ),
          onChanged: (_) => setState(() {}),
        )
      ],
    );
  }
}

效果说明

  • 可自由调整paddingHorizontal/paddingVertical控制背景和文本的间距
  • 可自由调整borderRadius控制圆角大小,不会出现描边方案里圆角过大的问题
  • 相邻行自动合并圆角,完全消除行间隙
  • 支持动态输入,文本修改后背景实时同步更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 21:18:03