How can I be notified that a repaint occurred in the child tree?

Viewed 135

I need to take a snapshot of a widget (to generate an ui.Image) every time the widget or its children is repaint.

To take the snapshot of a widget I use a RepaintBoundary and it generate correctly the image with a _captureImage method.

How can I be notified that a repaint occurred in the child tree to call _captureImage only when it is needed (that is every time the visual representation of the child change)?

Here is a simplified version of my current widget.

class AutoSnapshotWidget extends StatefulWidget {
  const AutoSnapshotWidget({
    Key? key,
    required this.child,
    required this.onChange,
  }) : super(key: key);

  final Widget child;
  final void Function(ui.Image) onChange;

  @override
  State<AutoSnapshotWidget> createState() => _AutoSnapshotWidgetState();
}

class _AutoSnapshotWidgetState extends State<AutoSnapshotWidget> {
  final _key = GlobalKey();

  // *****************************************************************
  // How to make this function called every time the child is repaint?
  // *****************************************************************  
  void _captureImage() async {
    final buildContext = _key.currentContext! as SingleChildRenderObjectElement;
    final boundary = buildContext.findRenderObject()! as RenderRepaintBoundary;
    final image = await boundary.toImage();
    widget.onChange(image);
  }

  @override
  Widget build(BuildContext context) {
    return RepaintBoundary(
      key: _key,
      child: widget.child,
    );
  }
}
1 Answers

If you'd like, you can take a snapshot every time your widget is done rebuilding. Make use of WidgetsBinding.instance.addPostFrameCallback() to do that by editing your build method like so:

  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance
        .addPostFrameCallback((_) => _captureImage());
    return RepaintBoundary(
      key: _key,
      child: widget.child,
    );
  }
Related