Search code examples
flutterflutter-layout

Flutter: How to make a Container shape with corner border


I have this piece of code.

 Container(
      decoration: BoxDecoration(
        color: Colors.red,
        borderRadius: BorderRadius.circular(18),
      ),
      child: Center(
        child: Text(
          'Monday',
          style: TextStyle(
            color: Colors.white,
            fontSize: 30,
          ),
        ),
      ),
    );

That produces this

enter image description here

But I want something that looks like this.

enter image description here


Solution

  • By Knowing CustomPainter widget's paint

    
    class MyCustomPainter extends CustomPainter {
      final double padding;
      final double frameSFactor;
    
      MyCustomPainter({
        required this.padding,
        required this.frameSFactor,
      });
      @override
      void paint(Canvas canvas, Size size) {
        final frameHWidth = size.width * frameSFactor;
    
        Paint paint = Paint()
          ..color = Colors.redAccent
          ..strokeCap = StrokeCap.round
          ..style = PaintingStyle.fill
          ..strokeWidth = 4;
    
        /// background
        canvas.drawRRect(
            RRect.fromRectAndRadius(
              Rect.fromLTRB(0, 0, size.width, size.height),
              Radius.circular(18),
            ),
            paint);
    
        /// top left
        canvas.drawLine(
          Offset(0 + padding, padding),
          Offset(
            padding + frameHWidth,
            padding,
          ),
          paint..color = Colors.black,
        );
    
        canvas.drawLine(
          Offset(0 + padding, padding),
          Offset(
            padding,
            padding + frameHWidth,
          ),
          paint..color = Colors.black,
        );
    
        /// top Right
        canvas.drawLine(
          Offset(size.width - padding, padding),
          Offset(size.width - padding - frameHWidth, padding),
          paint..color = Colors.black,
        );
        canvas.drawLine(
          Offset(size.width - padding, padding),
          Offset(size.width - padding, padding + frameHWidth),
          paint..color = Colors.black,
        );
    
        /// Bottom Right
        canvas.drawLine(
          Offset(size.width - padding, size.height - padding),
          Offset(size.width - padding - frameHWidth, size.height - padding),
          paint..color = Colors.black,
        );
        canvas.drawLine(
          Offset(size.width - padding, size.height - padding),
          Offset(size.width - padding, size.height - padding - frameHWidth),
          paint..color = Colors.black,
        );
    
        /// Bottom Left
        canvas.drawLine(
          Offset(0 + padding, size.height - padding),
          Offset(0 + padding + frameHWidth, size.height - padding),
          paint..color = Colors.black,
        );
        canvas.drawLine(
          Offset(0 + padding, size.height - padding),
          Offset(0 + padding, size.height - padding - frameHWidth),
          paint..color = Colors.black,
        );
      }
    @override 
    bool shouldRepaint(covariant CustomPainter oldDelegate) => true; //based on your use-cases
     }
    

    And use Like

      SizedBox(
                    height: 200,
                    width: 200,
                    child: CustomPaint(
                      painter: MyCustomPainter(frameSFactor: .1, padding: 20),
                      child: Center(
                        child: Text(
                          'With Painter',
                          style: TextStyle(
                            color: Colors.black,
                            fontSize: 30,
                          ),
                        ),
                      ),
                    ),
                  ),
    

    Also using Container decoration

    
    
    class CustomDecoration extends Decoration {
      final Color? backgroundColor;
      final double frameSFactor;
      //defalut padding _Need to check
      final double gap;
    
      CustomDecoration({
        this.backgroundColor = Colors.transparent,
        required this.frameSFactor,
        required this.gap,
      });
      @override
      BoxPainter createBoxPainter([VoidCallback? onChanged]) {
        return CustomDecorationPainter(
            backgroundColor: backgroundColor!,
            frameSFactor: frameSFactor,
            padding: gap);
      }
    }
    
    class CustomDecorationPainter extends BoxPainter {
      final Color backgroundColor;
      final double frameSFactor;
      final double padding;
    
      CustomDecorationPainter({
        required this.backgroundColor,
        required this.frameSFactor,
        required this.padding,
      });
    
      @override
      void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
        print(configuration.size!.height);
    
        final Rect bounds = offset & configuration.size!;
        final frameHWidth = configuration.size!.width * frameSFactor;
    
        Paint paint = Paint()
          ..color = backgroundColor
          ..strokeCap = StrokeCap.round
          ..style = PaintingStyle.fill
          ..strokeWidth = 4;
    
        /// background
        canvas.drawRRect(
            RRect.fromRectAndRadius(
              bounds,
              Radius.circular(18),
            ),
            paint..color = Colors.redAccent);
    
        paint.color = Colors.black;
    
        /// top left
        canvas.drawLine(
          bounds.topLeft + Offset(padding, padding),
          Offset(bounds.topLeft.dx + frameHWidth, bounds.topLeft.dy) +
              Offset(padding, padding),
          paint,
        );
        canvas.drawLine(
          bounds.topLeft + Offset(padding, padding),
          Offset(bounds.topLeft.dx, bounds.topLeft.dy + frameHWidth) +
              Offset(padding, padding),
          paint,
        );
    
        //top Right
        canvas.drawLine(
          Offset(bounds.topRight.dx - padding, bounds.topRight.dy + padding),
          Offset(bounds.topRight.dx - padding - frameHWidth,
              bounds.topRight.dy + padding),
          paint,
        );
        canvas.drawLine(
          Offset(bounds.topRight.dx - padding, bounds.topRight.dy + padding),
          Offset(bounds.topRight.dx - padding,
              bounds.topRight.dy + padding + frameHWidth),
          paint..color,
        );
    
        //bottom Right
        canvas.drawLine(
          Offset(bounds.bottomRight.dx - padding, bounds.bottomRight.dy - padding),
          Offset(bounds.bottomRight.dx - padding,
              bounds.bottomRight.dy - padding - frameHWidth),
          paint,
        );
        canvas.drawLine(
          Offset(bounds.bottomRight.dx - padding, bounds.bottomRight.dy - padding),
          Offset(bounds.bottomRight.dx - padding - frameHWidth,
              bounds.bottomRight.dy - padding),
          paint,
        );
    //bottom Left
        canvas.drawLine(
          Offset(bounds.bottomLeft.dx + padding, bounds.bottomLeft.dy - padding),
          Offset(bounds.bottomLeft.dx + padding,
              bounds.bottomLeft.dy - padding - frameHWidth),
          paint,
        );
        canvas.drawLine(
          Offset(bounds.bottomLeft.dx + padding, bounds.bottomLeft.dy - padding),
          Offset(bounds.bottomLeft.dx + padding + frameHWidth,
              bounds.bottomLeft.dy - padding),
          paint,
        );
      }
    }
    

    And use like

    
     SizedBox(
                    width: 200,
                    height: 200,
                    child: Container(
                      alignment: Alignment.center,
                      decoration: CustomDecoration(
                        frameSFactor: .1,
                        gap: 20,
                      ),
                      child: Text("With Decoration"),
                    ),
                  ),
    

    you can add the button the way you like

    enter image description here