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

如何在Flutter中创建三角形徽章?

Flutter 三角形徽章实现方案

既然flutter_badges库无法实现三角形徽章的需求,不用硬改库,直接自己实现更简单。以下两种方案可以快速达到你要的效果:

方法一:ClipPath 快速实现基础三角形徽章

这种方式适合制作固定方向的三角角标,代码简洁易维护。

自定义徽章组件

class TriangleBadge extends StatelessWidget {
  final String text;
  final Color badgeColor;
  final Color textColor;
  final double size;

  const TriangleBadge({
    super.key,
    required this.text,
    this.badgeColor = Colors.red,
    this.textColor = Colors.white,
    this.size = 30,
  });

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: size,
      height: size,
      child: ClipPath(
        clipper: TriangleClipper(),
        child: Container(
          color: badgeColor,
          child: Center(
            child: Text(
              text,
              style: TextStyle(
                color: textColor,
                fontSize: size * 0.4,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

// 自定义裁剪器,绘制右上角三角路径
class TriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.moveTo(size.width, 0); // 起点:右上角
    path.lineTo(size.width, size.height); // 到右下角
    path.lineTo(0, 0); // 到左上角
    path.close(); // 闭合路径
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}

使用示例

把徽章放在目标Widget的右上角,用Stack定位:

Stack(
  children: [
    // 你的目标组件(比如卡片、图片)
    Container(
      width: 100,
      height: 100,
      color: Colors.grey[200],
      child: const Center(child: Text("目标组件")),
    ),
    // 三角形徽章
    const Positioned(
      top: 0,
      right: 0,
      child: TriangleBadge(text: "3"),
    ),
  ],
)

方法二:CustomPaint 实现带边框的灵活三角形

如果需要带边框、自定义三角方向等复杂样式,用CustomPaint直接绘制更灵活。

带边框的徽章组件

class CustomTriangleBadge extends StatelessWidget {
  final String text;
  final Color badgeColor;
  final Color textColor;
  final Color borderColor;
  final double borderWidth;
  final double size;

  const CustomTriangleBadge({
    super.key,
    required this.text,
    this.badgeColor = Colors.red,
    this.textColor = Colors.white,
    this.borderColor = Colors.black,
    this.borderWidth = 1,
    this.size = 30,
  });

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: size,
      height: size,
      child: CustomPaint(
        painter: TrianglePainter(
          color: badgeColor,
          borderColor: borderColor,
          borderWidth: borderWidth,
        ),
        child: Center(
          child: Text(
            text,
            style: TextStyle(
              color: textColor,
              fontSize: size * 0.4,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
      ),
    );
  }
}

// 自定义绘制器,支持填充和边框
class TrianglePainter extends CustomPainter {
  final Color color;
  final Color borderColor;
  final double borderWidth;

  TrianglePainter({
    required this.color,
    required this.borderColor,
    required this.borderWidth,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // 填充画笔
    final fillPaint = Paint()
      ..color = color
      ..style = PaintingStyle.fill;

    // 边框画笔
    final borderPaint = Paint()
      ..color = borderColor
      ..style = PaintingStyle.stroke
      ..strokeWidth = borderWidth;

    // 绘制右上角三角路径
    final path = Path();
    path.moveTo(size.width, 0);
    path.lineTo(size.width, size.height);
    path.lineTo(0, 0);
    path.close();

    // 先画填充,再画边框
    canvas.drawPath(path, fillPaint);
    canvas.drawPath(path, borderPaint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    final old = oldDelegate as TrianglePainter;
    return color != old.color ||
        borderColor != old.borderColor ||
        borderWidth != old.borderWidth;
  }
}

调整三角方向

如果需要其他方向的三角,修改TrianglePainter中的路径即可:

  • 左上角三角:
    path.moveTo(0, 0);
    path.lineTo(size.width, 0);
    path.lineTo(0, size.height);
    path.close();
    
  • 左下角三角:
    path.moveTo(0, size.height);
    path.lineTo(size.width, size.height);
    path.lineTo(0, 0);
    path.close();
    

注意事项

  • 如果文本过长,可调整fontSize参数,或者根据文本长度动态计算徽章size;
  • 若文本位置偏移,可给Text添加Padding,或用Transform.translate微调位置;
  • 两种方案都可以直接集成到现有项目,无需依赖第三方库,避免扩展flutter_badges带来的兼容性问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 10:07:51