Search code examples
flutterdartflutter-layoutwidget

how to draw a container like puzzle piece


I want to create a Container widget like below. Can anybody help? enter image description here


Solution

  • I'm using ShapeBorder,

    class MyCardShape extends ShapeBorder {
      @override
      EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
    
      @override
      ShapeBorder scale(double t) => this;
    
      @override
      Path getInnerPath(Rect rect, {TextDirection? textDirection}) {
        return getOuterPath(rect, textDirection: textDirection);
      }
    
      @override
      Path getOuterPath(Rect rect, {TextDirection? textDirection}) {
        Path path = Path()..fillType = PathFillType.evenOdd;
        const radius = Radius.circular(16);
    
        final holeGap = rect.height * .15;
    
        final rrect = RRect.fromRectAndCorners(rect,
            bottomLeft: radius,
            bottomRight: radius,
            topLeft: radius,
            topRight: radius);
    
        final holePath = Path()
          ..addOval(
            Rect.fromCircle(
              center: Offset(rect.left, rect.top + rect.height / 2),
              radius: holeGap,
            ),
          )
          ..addOval(
            Rect.fromCircle(
              center: Offset(rect.right, rect.top + rect.height / 2),
              radius: holeGap,
            ),
          );
    
        final path1 = path
          ..addPath(holePath, Offset.zero)
          ..addRRect(rrect);
    
        final result = path1;
        return result;
      }
    
      @override
      void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {}
    }
    

    enter image description here

    And using with ClipRRect to cover the extra shape, you can choose arcToPoint on paint or different methods.

    class UITest extends StatelessWidget {
      const UITest({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.deepPurple,
          body: Center(
            child: Padding(
              padding: const EdgeInsets.all(8.0),
              child: ClipRRect(
                // clipping extra
                child: Container(
                  width: 400,
                  height: 100,
                  clipBehavior: Clip
                      .antiAlias, // not sure why this is not working on shape decoration
                  decoration: ShapeDecoration(
                    shape: MyCardShape(),
                    color: Colors.amber,
                  ),
                ),
              ),
            ),
          ),
        );
      }
    }