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

Flutter中如何在Container内实现带圆角的自定义三角形遮罩?

实现带圆角边框的遮罩三角形(Flutter)

我已经完成了卡片Widget的编码,现在需要在卡片内创建自定义三角形形状并添加遮罩,同时让三角形带有圆角边框。之前尝试用CustomPaint实现,但效果不理想,恳请提供可行方案。

现有卡片代码

//Card form fulfiled by IMG from the profile
Container(
  height: MediaQuery.of(context).size.height / 1.5533,
  width: MediaQuery.of(context).size.width / 1.075,
  decoration: const BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.all(Radius.circular(20)),
    boxShadow: [
      BoxShadow(
        color: Colors.grey,
        spreadRadius: 1,
        blurRadius: 10,
        blurStyle: BlurStyle.outer,
      )
    ],
    image: DecorationImage(
      image: AssetImage('assets/img1.JPG'),
      fit: BoxFit.cover,
    ),
  ),
),
//The rectangle containing Nickname & Tags
Positioned(
    top: 20,
    right: 20,
    child: ClipRRect(
        borderRadius: BorderRadius.circular(20),
        child: BackdropFilter(
            filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
            child: Opacity(
                opacity: 0.3,
                child: Container(
                  height:
                      MediaQuery.of(context).size.height / 9.6082474,
                  width: MediaQuery.of(context).size.width / 2.1182266,
                  decoration: const BoxDecoration(
                    color: Color(0XFFD9D9D9),
                  ),
                ))))),
//The Nickname of the user
Positioned(
    top: 15,
    right: 25,
    child: ClipRRect(
        borderRadius: BorderRadius.circular(20),
        child: userNickname("Paul", context))),
// Tags
Positioned(
    top: 90, right: 90, child: tags("#EFREI", context, Colors.purple)),

//The code for the red and green triangle to insert

之前尝试的CustomPaint代码

调用代码

Positioned(
        top: 360,
        child: CustomPaint(
          painter: CustomShape(blurSigma: 30),
        ))

CustomShape类

class CustomShape extends CustomPainter {
  double blurSigma;
  CustomShape({required this.blurSigma});
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint();
    // TODO: Set properties to paint
    paint.color = const Color(0XFFFF0000).withOpacity(0.8);
    paint.maskFilter = MaskFilter.blur(BlurStyle.inner, blurSigma);
    var path = Path();
    // TODO: Draw your path
    path.lineTo(100, 240);
    path.lineTo(0, 240);

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

解决方案

方法一:改进CustomPaint实现圆角三角形+遮罩

要实现带圆角的三角形,需要用Path的arcToPoint处理圆角,同时结合遮罩效果。下面是修改后的CustomShape:

class RoundedTrianglePainter extends CustomPainter {
  final Color color;
  final double blurSigma;
  final double cornerRadius;

  RoundedTrianglePainter({
    required this.color,
    required this.blurSigma,
    this.cornerRadius = 8.0,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color.withOpacity(0.8)
      ..maskFilter = MaskFilter.blur(BlurStyle.inner, blurSigma);

    final path = Path();
    // 定义三角形三个顶点(示例:右下角直角三角形,可根据设计调整坐标)
    final point1 = Offset(size.width, 0);
    final point2 = Offset(size.width, size.height);
    final point3 = Offset(0, size.height);

    // 绘制带圆角的三角形路径
    path.moveTo(point1.dx - cornerRadius, point1.dy);
    path.arcToPoint(
      Offset(point1.dx, point1.dy + cornerRadius),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    path.lineTo(point2.dx, point2.dy - cornerRadius);
    path.arcToPoint(
      Offset(point2.dx - cornerRadius, point2.dy),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    path.lineTo(point3.dx + cornerRadius, point3.dy);
    path.arcToPoint(
      Offset(point3.dx, point3.dy - cornerRadius),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    path.close();

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant RoundedTrianglePainter oldDelegate) {
    return oldDelegate.color != color ||
        oldDelegate.blurSigma != blurSigma ||
        oldDelegate.cornerRadius != cornerRadius;
  }
}

调用时指定大小和位置:

Positioned(
  top: 360,
  left: 0,
  child: SizedBox(
    width: 100,
    height: 100,
    child: CustomPaint(
      painter: RoundedTrianglePainter(
        color: Colors.red,
        blurSigma: 30,
        cornerRadius: 10,
      ),
    ),
  ),
),
// 绿色三角形同理
Positioned(
  top: 360,
  right: 0,
  child: SizedBox(
    width: 100,
    height: 100,
    child: CustomPaint(
      painter: RoundedTrianglePainter(
        color: Colors.green,
        blurSigma: 30,
        cornerRadius: 10,
      ),
    ),
  ),
),

方法二:用ClipPath + Container实现带边框的圆角三角形

如果需要同时显示边框,可以用ClipPath结合Container,再叠加遮罩:

class RoundedTriangleClipper extends CustomClipper<Path> {
  final double cornerRadius;

  RoundedTriangleClipper({this.cornerRadius = 8.0});

  @override
  Path getClip(Size size) {
    final path = Path();
    final point1 = Offset(size.width, 0);
    final point2 = Offset(size.width, size.height);
    final point3 = Offset(0, size.height);

    path.moveTo(point1.dx - cornerRadius, point1.dy);
    path.arcToPoint(
      Offset(point1.dx, point1.dy + cornerRadius),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    path.lineTo(point2.dx, point2.dy - cornerRadius);
    path.arcToPoint(
      Offset(point2.dx - cornerRadius, point2.dy),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    path.lineTo(point3.dx + cornerRadius, point3.dy);
    path.arcToPoint(
      Offset(point3.dx, point3.dy - cornerRadius),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    );
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant RoundedTriangleClipper oldDelegate) {
    return oldDelegate.cornerRadius != cornerRadius;
  }
}

使用时:

Positioned(
  top: 360,
  left: 0,
  child: SizedBox(
    width: 100,
    height: 100,
    child: ClipPath(
      clipper: RoundedTriangleClipper(cornerRadius: 10),
      child: BackdropFilter(
        filter: ImageFilter.blur(sigmaX: 30, sigmaY: 30),
        child: Container(
          color: Colors.red.withOpacity(0.8),
          decoration: BoxDecoration(
            border: Border.all(color: Colors.white, width: 2), // 边框
          ),
        ),
      ),
    ),
  ),
),

关键说明

  • 两种方法都可实现圆角三角形,方法一更适合纯形状绘制,方法二更适合需要边框或复杂装饰的场景
  • 坐标点可根据Figma设计调整,示例用的是右下角直角三角形,修改顶点坐标即可适配需求
  • 遮罩效果通过MaskFilter(CustomPaint)或BackdropFilter(ClipPath)实现,按需选择

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 05:47:52