title: How to ensure my CustomPaint widget painting is stored in the raster cache?
body: <p>I have an app that displays a black dot at the point where the user touches the screen like this:</p>
  
  <p><a href="https://i.stack.imgur.com/YpTDS.png" rel="noreferrer"><img src="https://i.stack.imgur.com/YpTDS.png" alt="enter image description here"></a></p>
  
  <p>The black dot can be moved by the user as he/she drags his finger on the screen.</p>
  
  <p>The background is an expensive paint operation, so I have created two separate widgets in a stack, hoping that the background widget painting will be stored in the Flutter raster cache.  But it's not stored - Flutter calls my expensive paint method every time the black dot moves.</p>
  
  <p>What am I doing wrong?</p>
  
  <p>Here's my code:</p>
  
  <pre><code>import 'package:flutter/material.dart';
  import 'dart:math';
  
  void main() {
    runApp(new MyApp());
  }
  
  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return new MaterialApp(
        home: new MyHomePage(),
      );
    }
  }
  
  class MyHomePage extends StatefulWidget {
    @override
    State createState() =&gt; new MyHomePageState();
  }
  
  class MyHomePageState extends State&lt;MyHomePage&gt; {
    GlobalKey _paintKey = new GlobalKey();
    Offset _offset;
  
    @override
    Widget build(BuildContext context) {
      return new Scaffold(
        body: new Stack(
          fit: StackFit.expand,
          children: &lt;Widget&gt;[
            new CustomPaint(
              painter: new ExpensivePainter(),
              isComplex: true,
              willChange: false,
            ),
            new Listener(
              onPointerDown: _updateOffset,
              onPointerMove: _updateOffset,
              child: new CustomPaint(
                key: _paintKey,
                painter: new MyCustomPainter(_offset),
                child: new ConstrainedBox(
                  constraints: new BoxConstraints.expand(),
                ),
              ),
            )
          ],
        ),
      );
    }
  
    _updateOffset(PointerEvent event) {
      RenderBox referenceBox = _paintKey.currentContext.findRenderObject();
      Offset offset = referenceBox.globalToLocal(event.position);
      setState(() {
        _offset = offset;
      });
    }
  }
  
  class ExpensivePainter extends CustomPainter {
    @override
    void paint(Canvas canvas, Size size) {
      print("Doing expensive paint job");
      Random rand = new Random(12345);
      List&lt;Color&gt; colors = [
        Colors.red,
        Colors.blue,
        Colors.yellow,
        Colors.green,
        Colors.white,
      ];
      for (int i = 0; i &lt; 5000; i++) {
        canvas.drawCircle(
            new Offset(
                rand.nextDouble() * size.width, rand.nextDouble() * size.height),
            10 + rand.nextDouble() * 20,
            new Paint()
              ..color = colors[rand.nextInt(colors.length)].withOpacity(0.2));
      }
    }
  
    @override
    bool shouldRepaint(ExpensivePainter other) =&gt; false;
  }
  
  class MyCustomPainter extends CustomPainter {
    final Offset _offset;
  
    MyCustomPainter(this._offset);
  
    @override
    void paint(Canvas canvas, Size size) {
      if (_offset == null) return;
      canvas.drawCircle(_offset, 10.0, new Paint()..color = Colors.black);
    }
  
    @override
    bool shouldRepaint(MyCustomPainter other) =&gt; other._offset != _offset;
  }
  </code></pre>