Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is shouldRepaint method from custom painter class in flutter called?

Tags:

flutter

I'm trying to understand how shouldRepaint works. I found a tutorial that paints a dial around a circle button to show its value. The example had shouldRepaint always return true. Basically it just paints a partial circle around the button to show the % value. If the value is 50, the circle would go half way around.

I set shouldRepaint to always return false to see what would happen. It still painted the button circle correctly.

My theory is that it will always paint when the stateful widget is redrawn. So when the button value goes from 40% to 50%, the widget redraws and the painting is done no matter what.

So if my widget is painted anyway when the state changes, when would I use shouldRepaint?

Here is the relevant code from the tutorial:

class HomeContent extends StatefulWidget {
  @override
  _HomeContentState createState() => _HomeContentState();
}

class _HomeContentState extends State<HomeContent> {
  int percentage;

  @override
  void initState() {
    super.initState();
    setState(() {
      percentage = 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Container(
        height: 200.0,
        width: 200.0,
        child: new CustomPaint(
          foregroundPainter: new MyPainter(
              lineColor: Colors.amber,
          completeColor: Colors.blueAccent,
          completePercent: percentage,
          width: 8.0),
          child: new Padding(
          padding: const EdgeInsets.all(8.0),
        child: new RaisedButton(
            color: Colors.purple,
            splashColor: Colors.blueAccent,
            shape: new CircleBorder(),
            child: new Text("$percentage%"),
            onPressed: () {
              setState(() {
                percentage += 10;
                if (percentage > 100) {
                  percentage = 0;
                }
              });
            }),
          ),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  Color lineColor;
  Color completeColor;
  int completePercent;
  double width;

  MyPainter(
  {this.lineColor, this.completeColor, this.completePercent, this.width});

  @override
  void paint(Canvas canvas, Size size) {
    Paint line = new Paint()
      ..color = lineColor
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = width;
    Paint complete = new Paint()
      ..color = completeColor
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke
      ..strokeWidth = width;
    Offset center = new Offset(size.width / 2, size.height / 2);
    double radius = min(size.width / 2, size.height / 2);
    canvas.drawCircle(center, radius, line);
    double arcAngle = 2 * pi * (completePercent / 100.0);
    if (arcAngle >= 2 * pi) arcAngle = 2 * pi - 0.001;  // cannot draw a complete circle arc
    canvas.drawArc(new Rect.fromCircle(center: center, radius: radius), -pi / 2,
    arcAngle, false, complete);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}
like image 836
shawnlg Avatar asked May 30 '19 02:05

shawnlg


People also ask

How do you use custom painters in flutter?

Custom Painter is : A widget that provides a canvas on which to draw during the paint phase. :To paint in Flutter you can use the CustomPaint widget which basically takes size of its parent if not given the child . The CustomPainter subclass overrides two methods: paint() and shouldRepaint() .


1 Answers

From Docs, shouldRepaint():

If the new instance represents different information than the old instance, then the method should return true, otherwise it should return false

Also,

It's possible that the paint method will get called even if shouldRepaint returns false (e.g. if an ancestor or descendant needed to be repainted). It's also possible that the paint method will get called without shouldRepaint being called at all (e.g. if the box changes size)


So, a good way would be to use

@override
bool shouldRepaint(MyPainter oldDelegate) => 
    oldDelegate.completePercent != completePercent;
like image 156
CopsOnRoad Avatar answered Nov 13 '22 04:11

CopsOnRoad