Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter CustomPaint is not repainting

I can't make the custom painter repaint. I tried to use Listenable, callbacks, setState and nothing repaints the screen.

The docs says this:

The most efficient way to trigger a repaint is to either:

  • Extend this class and supply a repaint argument to the constructor of the CustomPainter, where that object notifies its listeners when it is time to repaint.
  • Extend Listenable (e.g. via ChangeNotifier) and implement CustomPainter, so that the object itself provides the notifications directly. In either case, the CustomPaint widget or RenderCustomPaint render object will listen to the Listenable and repaint whenever the animation ticks, avoiding both the build and layout phases of the pipeline.

But the code don't work as intended.

This is the code I'm using:

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

main() {
  runApp(MaterialApp(
    home: Scaffold(appBar: AppBar(), body: Pad()),
  ));
}

class Pad extends StatefulWidget {
  @override
  _PadState createState() => _PadState();
}

class _PadState extends State<Pad> {
  @override
  Widget build(BuildContext context) {
    final painter = Painter();
    return GestureDetector(
        onTap: () {
          setState(() {
            painter.addY(10);
          });
        },
        child: CustomPaint(
          painter: painter,
          child: Container(),
        ));
  }
}

class Painter extends CustomPainter {
  double y = 10;

  addY(val) {
    y += val;
  }

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawCircle(Offset(size.width / 2, y++), 100, Paint());
  }

  @override
  bool shouldRepaint(Painter oldDelegate) {
    return true;
  }
}
like image 662
Guilherme Avatar asked Oct 24 '25 02:10

Guilherme


2 Answers

Listenable works just fine, use ValueNotifier for example, see https://github.com/pskink/matrix_gesture_detector/blob/master/example/lib/custom_painter_demo.dart for some sample code

like image 84
pskink Avatar answered Oct 26 '25 16:10

pskink


I don't know why but when I add an empty DropdownButtonFormField widget, It worked.

Even shouldRepaint function always return false. The paint function always re-call when tap to GestureDetector.

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

main() {
  runApp(MaterialApp(
    home: Scaffold(appBar: AppBar(), body: const Pad()),
  ));
}

class Pad extends StatefulWidget {
  const Pad({Key? key}) : super(key: key);

  @override
  _PadState createState() => _PadState();
}

class _PadState extends State<Pad> {
  @override
  Widget build(BuildContext context) {
    final painter = Painter();
    return Stack(
      children: [
        SizedBox(
          width: 0,
          height: 0,
          child: DropdownButtonFormField<String>(
              onChanged: (value) {}, items: const []),
        ),
        GestureDetector(
            onTap: () {
              setState(() {
                painter.addY(10);
              });
            },
            child: CustomPaint(
              painter: Painter(),
              child: Container(),
            )),
      ],
    );
  }
}

class Painter extends CustomPainter {
  double y = 10;

  addY(val) {
    y += val;
  }

  @override
  void paint(Canvas canvas, Size size) {
    debugPrint('paint');
    canvas.drawCircle(Offset(size.width / 2, y++), 100, Paint());
  }

  @override
  bool shouldRepaint(Painter oldDelegate) {
    return false;
  }
}
like image 33
Đức Hải Trần Avatar answered Oct 26 '25 15:10

Đức Hải Trần