flutter: custom shape as text background

Viewed 540

I need to achieve this in flutter:

enter image description here

I tried making a Row and setting a background to the Text to handle the ractangle, then a ClipPath to make the triangle. The problem with this is that the edge is not precise (you can see a thin line between the rectangle and the triangle in the image below), also the ClipPath has fixed size so if I want to change the text size at some point I'll have to fine-tune the triangle again.

enter image description here

here's my code:

class TriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(0.0, size.height);
    path.lineTo(size.width / 3, size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(TriangleClipper oldClipper) => false;
}

Row(
        children: [
          Container(
            color: Colors.orange,
            child: Padding(
              padding: const EdgeInsets.all(4.0),
              child: Text(
                "a label",
              ),
            ),
          ),
          ClipPath(
            clipper: TriangleClipper(),
            child: Container(
              color: Colors.orange,
              height: 23,
              width: 20,
            ),
          )
        ],
      )

I though using double.infinity instead of fixed size in ClipPath's child would solve it but doing that makes the triangle disappear (probably it becomes too big that I can't see it or goes behind something).

What is the correct way to approache this problem? I guess I could draw the trapezoid using a ClipPath, but how to make it so the width of it adapts to the lenght of the Text?

2 Answers

You can try the following code:

import 'dart:ui' as ui;

child: CustomPaint(
  size: Size(WIDTH,(WIDTH*0.625).toDouble()), //You can Replace [WIDTH] with your desired width for Custom Paint and height will be calculated automatically
  painter: RPSCustomPainter(),
),


class RPSCustomPainter extends CustomPainter{
  
  @override
  void paint(Canvas canvas, Size size) {
    
    

  Paint paint_0 = new Paint()
      ..color = Color.fromARGB(255, 33, 150, 243)
      ..style = PaintingStyle.fill
      ..strokeWidth = 1;
    paint_0.shader = ui.Gradient.linear(Offset(size.width*0.29,size.height*0.28),Offset(size.width*0.29,size.height*0.28),[Color(0xff7c1010),Color(0xffffffff)],[0.00,1.00]); 
         
    Path path_0 = Path();
    path_0.moveTo(size.width*0.2937500,size.height*0.2780000);

    canvas.drawPath(path_0, paint_0);
  

  Paint paint_1 = new Paint()
      ..color = Color.fromARGB(255, 33, 150, 243)
      ..style = PaintingStyle.fill
      ..strokeWidth = 1;
     
         
    Path path_1 = Path();
    path_1.moveTo(size.width*0.3750000,size.height*0.4000000);
    path_1.lineTo(size.width*0.5000000,size.height*0.4000000);
    path_1.lineTo(size.width*0.5375000,size.height*0.5000000);
    path_1.lineTo(size.width*0.3750000,size.height*0.5000000);
    path_1.lineTo(size.width*0.3750000,size.height*0.4000000);
    path_1.close();

    canvas.drawPath(path_1, paint_1);
  
    
  }

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

enter image description here

You can try it by yourself: https://shapemaker.web.app/#/

One way to achieve this is like so.

class TriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final w = size.width;
    final h = size.height;
    final triangleWidth = 10;

    final path = Path();
    path.lineTo(0, 0);
    path.lineTo(0, h);
    path.lineTo(w, h);
    path.lineTo(w - triangleWidth, 0);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(TriangleClipper oldClipper) => false;
}

and use it like so.

ClipPath(
    clipper: TriangleClipper(),
    child: Container(
      padding: EdgeInsets.fromLTRB(4, 4, 14, 4),   // 4 + triangleWidth for right padding
      color: Colors.orange,
      child: Text('A label'),
    ),
),
Related