CustomPainter in Flutter repaints on each frame during another animation

Viewed 494

In my Flutter project, I have a widget where there is a CustomPaint, and another widget. That other widget only is animated.

But for some reason, the paint() function on the CustomPainter is called on each frame, even though it's not animated.

Here is a sample code:

class TestAnimationPage extends StatefulWidget {
  @override
  _TestAnimationPageState createState() => _TestAnimationPageState();
}

class _TestAnimationPageState extends State<TestAnimationPage> with SingleTickerProviderStateMixin {

  AnimationController _controller;
  Animation<double> _animation;


  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 3000));
    _animation = Tween<double>(
        begin: 0,
        end: 700).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Interval(0, 1, curve: Curves.linear),
      ),
    );
    _controller.repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: [
            SizedBox(
              width: 1280,
              height: 800,
              child: CustomPaint(
                painter: TestPainter(),
              ),
            ),
            AnimatedBuilder(
              animation: _controller,
              builder: (BuildContext context, Widget child) =>
                Positioned(
                  left: 0,
                  top: _animation.value,
                  child: Container(
                    width: 1200,
                    height: 700,
                    color: Colors.redAccent,
                  ),
                ),
            ),
          ],
        ),
      ),
    );
  }
}

class TestPainter extends CustomPainter {

  TestPainter() {
    print("this log appears only once");
  }

  @override
  void paint(Canvas canvas, Size size) {
    print("this log appears on each frame");
    canvas.drawCircle(Offset.zero, 500, Paint()..color = Colors.amber);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

And here is what I see in the console:

I/flutter (11311): this log appears only once
I/flutter (11311): this log appears on each frame
I/flutter (11311): this log appears on each frame
I/flutter (11311): this log appears on each frame
I/flutter (11311): this log appears on each frame
I/flutter (11311): this log appears on each frame
I/flutter (11311): this log appears on each frame
I/flutter (11311): this log appears on each frame
I/flutter (11311): this log appears on each frame
(and so on...)

Because of those multiple paint() calls, the performance of my animation is getting pretty bad.

So why is it that the paint() function is called on each frame, and how can I prevent that?

Thanks.

1 Answers

OK so the solution is very simple (thanks again @pskink): just wrap the CustomPaint in a RepaintBoundary widget, to prevent the paint() function of the CustomPainter to be called on every frame.

So instead of this:

SizedBox(
  width: 1280,
  height: 800,
  child: CustomPaint(
    painter: TestPainter(),
  ),
),

do this:

RepaintBoundary(
  child: CustomPaint(
    size: Size(1280, 800)
    painter: TestPainter(),
  ),
),

Also, quite surprisingly, a good use of the isComplex attribute of CustomPaint widget might help a lot in some cases.

Related