Search code examples
flutterdartshadow

Flutter applying shadows to CustomPainted widget


Introduction

I draw a custom Tab-bar using Flutter's CustomPaint Widget it looks like this: Shape Image

In Addition, this is the code I used to draw the widget :

class TabBarPainter extends CustomPainter {
  final Color paintColor = Colors.redAccent 
  @override
  void paint(Canvas canvas, Size size) {
    /// the thing that I called as a deleter circle is an imaginary circle that I used to delete a semicircle from my rectangular shape

    var diameter = 80; /// X value is the diameter(R) of the deleter circle;
    double topSpace = 2;
    double startCurve = (size.width-diameter)/2; /// Start point of the curve
    double endCurve = startCurve+diameter; // End Point of the curve


     /// Some math about my cubic bezier curve
    double xValueInset = diameter * 0.05; 
    double yValueOffset = (diameter/2) * 4.0 / 3.0; 

    Path path = Path();

    Paint paint = Paint();

    /// Points to make a semicircle approximation using Bezier Curve
    var firstendPoint = new Offset(endCurve, topSpace);
    var controlPoint1  = new Offset(startCurve+xValueInset,yValueOffset+topSpace);
    var controlPoint2  = new Offset((diameter-xValueInset)+startCurve,yValueOffset+topSpace);

    //! Start sketching Shape
    path.moveTo(0.0,topSpace);
    path.lineTo(startCurve, topSpace);
    path.cubicTo(controlPoint1.dx, controlPoint1.dy,
    controlPoint2.dx, controlPoint2.dy,
    firstendPoint.dx, firstendPoint.dy);
    path.lineTo(size.width, topSpace);
    path.lineTo(size.width, size.height);
    path.lineTo(0.0, size.height);
    path.close();
    //! End sketching Shape

    paint.color = paintColor;

    canvas.drawPath(path, paint);

  }

  @override
  bool shouldRepaint(TabBarPainter oldDelegate) =>  oldDelegate != this;
}

Experimenting

I want to apply a shodow on my CustomDrawen Shape so I tried 2 methods:

First Method: I used a classical container and boxshadow to shadow it and it looked like this: Shape Image shadow Applied I used the following code :

Container(
  decoration: BoxDecoration(
    boxShadow: [
      BoxShadow(
        color : Colors.black.withOpacity(0.30),
        blurRadius: 3,
        ffset: new Offset(0, -3)
      )
    ]
  ),
  child: CustomPaint(           
    painter: TabBarPainter(),
  ),

Second Method : I drew a similar black colored(opacity(0.15)) shape and it looked like this:

Shape with a sub shape approximating the shadow

I added the following code to my CustomPainter in order to draw this shape:

final Color shadowColor = Colors.black.withOpacity(0.15);

Path shadowPath = Path();
Paint shadowPaint = Paint();

/// Points to make a semicircle approximation using Bezier Curve

var shadowfirstendPoint = new Offset(endCurve-topSpace, 0.0);
var shadowcontrolPoint1  = new Offset(startCurve+xValueInset+topSpace,yValueOffset);
var shadowcontrolPoint2  = new Offset((diameter-xValueInset)+startCurve-topSpace,yValueOffset);

//! Start sketching Shadow   
shadowPath.lineTo(startCurve+topSpace, 0.0);
shadowPath.cubicTo(shadowcontrolPoint1.dx, shadowcontrolPoint1.dy,
shadowcontrolPoint2.dx, shadowcontrolPoint2.dy,
shadowfirstendPoint.dx, shadowfirstendPoint.dy);
shadowPath.lineTo(size.width, 0.0);
shadowPath.lineTo(size.width, size.height);
shadowPath.lineTo(0.0, size.height);
shadowPath.close();

//! End Sketching Shadow
shadowPaint.color = shadowColor;
canvas.drawPath(shadowPath, shadowPaint);

Problem

In the first method, blank area - at the top center of widget - was filled with shadow

In the second method, shadow was not realistic because even though it had low opacity, it did not had a blur and I could not find a method to make it blurred

Conclusion

I need another way to properly shadow my widget or add blur to my shadow-like custom drawn shape

Since flutter is doing this to every type of widget they created, it seems possible

I would be thankful to any kind of helper

Regards


Solution

  • As @pskink mentioned, there is a method of canvas called drawShadow

    so changing my drawing method for my shadowPath to :

    canvas.drawShadow(shadowPath, Colors.black, 2.0, true);
    

    Will solve the problem and the output will be something like this : Final Image

    Thanks for everyone !!