title: Flutter keep background canvas drawing to skip repaint when only foreground changes
body: <p>I am working on a project that has a <code>CustomPaint</code> that draws shapes as a background, and when you tap the screen, it draws a circle on that specific position. I am using <code>GestureDetector</code> to get the tap data and send it as an argument to <code>_MyCustomPainter</code> Something similar to the code below:</p>
  <pre class="lang-dart prettyprint-override"><code>class MyApp extends StatefulWidget{
    @override
    _MyAppState createState() =&gt; _MyAppState();
  }
  
  class _MyAppState extends State&lt;MyApp&gt; {
  
    Offset _circlePosition = Offset(-1, -1);
  
    void setCirclePosition(Offset newPosition) {
      setState(() {
        this._circlePosition = newPosition;
      });
    }
  
    void clearCircle() {
      setState(() {
        this._circlePosition = Offset(-1, -1);
      });
    }
  
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        home: Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.green,
            title: Text('My app'),
          ),
          body: Container(
            child: GestureDetector(
              onTapDown: (detail) {
                setCirclePosition(detail.localPosition);
              },
              onHorizontalDragStart: (detail) {
                setCirclePosition(detail.localPosition);
              },
              onHorizontalDragUpdate: (detail) {
                setCirclePosition(detail.localPosition);
              },
              onVerticalDragStart: (detail) {
                setCirclePosition(detail.localPosition);
              },
              onVerticalDragUpdate: (detail) {
                setCirclePosition(detail.localPosition);
              },
              onTapUp: (detail) {
                clearCircle();
              },
              onVerticalDragEnd: (detail) {
                clearCircle();
              },
              onHorizontalDragEnd: (detail) {
                clearCircle();
              },
              child: LimitedBox(
                maxHeight: 400,
                maxWidth: 300,
                child: CustomPaint(
                  size: Size.infinite,
                  painter: new _MyCustomPainter(
                    circlePosition: circlePosition,
                  ),
                ),
              ),
            ),
          ),
        ),
      );
    }
  }
  
  class _MyCustomPainter extends CustomPainter {
    _MyCustomPainter({
      this.circlePosition,
    });
  
    final Offset circlePosition;
  
    void _drawBackground(Canvas canvas) {
      // draw the background
    }
  
    @override
    void paint(Canvas canvas, Size size) {
      _drawBackground(canvas);
      if (circlePosition.dx != -1 &amp;&amp; circlePosition.dy != -1) {
        // draws a circle on the position
        var circlePaint = Paint()..color = Colors.green;
        canvas.drawCircle(circlePosition, 5, circlePaint);
      }
    }
  
    @override
    bool shouldRepaint(_MyCustomPainter old) {
      return circlePosition.dx != old.circlePosition.dx ||
      circlePosition.dy != old.circlePosition.dy;
    }
  }
  </code></pre>
  <p>So the thing here is, every time the user moves the finger on the screen with a long tap the background that doesn't change is being repainted over and over, and there is a lot of code involved in painting this specific background. There is the <code>shouldRepaint</code> method but it signals to repaint the whole widget. How could I make so that the background is only drawn once, and than on repaint I just use the background I created previously? Is using a <code>PictureRecorder</code> to generate an image and than using that image on future repaints the best way to do this? and also should my <code>CustomPainter</code> extend <code>ChangeNotifier</code> for better performance? The current approach works, but I am wondering how could I improve it.</p>