skip to Main Content

We would like to add a line to drawing we drew earlier using the paint function of customPaint.
The following drawing will be displayed:

enter image description here

And we would like to change the drawing after a few seconds to the following drawing:

enter image description here

Meaning that a short line will be added to the original drawing.
The user will choose which drawing he saw before the drawing changed.
We tried to solve this problem with flutter timer and flutter future.dleay but nothing happened after the time we set and the debuger console showed: "Unhandled Exception: Object has been disposed".
We would be happy to know if there are other options that can help us reach our goal: different timing functions, another drawing option that works with a timer or future.delay
We tried to solve our problem with this function:

void paint(Canvas canvas, Size size){
const p1 = Offset(50, 50);
const p2 = Offset(50, 300);
const p3 = Offset(50, 50);
const p4 = Offset(250, 50);
const p5 = Offset(250, 50);
const p6 = Offset(250, 150);
const p7 = Offset(250, 150);
const p8 = Offset(250, 300);
final paint = Paint()
        ..color = Colors.black
       ..strokeWidth = 4
       ..strokeCap = StrokeCap.round;
canvas.drawLine(p1, p2, paint);
canvas.drawLine(p3, p4, paint);
canvas.drawLine(p5, p6, paint);
Timer(
      Duration(seconds: 1),
      () {
        canvas.drawLine(p7, p8, paint);
      },
    );'

this section located on the next line of the fucntion below

2

Answers


  1. The way the custom painter is implemented does not allow for any async calls on the canvas object as it is destroyed and the paint function is supplied with a new canvas object hence the error message that the old one was destroyed.

    You could achieve this delayed paint easily by using two custom painters within a stack and adding a delay to the second one.

    class DelayedDraw extends StatefulWidget {
      final Size size;
    
      const DelayedDraw({ super.key, required this.size });
    
      @override
      State< DelayedDraw > createState() => _ DelayedDraw State();
    }
    
    class _ DelayedDraw State extends State<DelayedDraw > {
      bool drawSecond = false;
    
      @override
      void initState() {
          super.initState();
          WidgetsBinding.instance!.addPostFrameCallback((_) => 
             Future.delayed(const Duration(seconds: 1))
                 .then((_) => setState(() => showSecond = true))
          );
      }
    
      @override
      Widget build(BuildContext context) {
        return Stack(
            children: [
                CustomPaint(
                    painter: BaseShapePainter(),
                    size: widget.size,
                ),
                if(drawSecond) 
                    CustomPaint(
                        painter: SecondShapePainter(),
                        size: widget.size,
                    ),
            ],
        );
      }
    }
    
    Login or Signup to reply.
  2. For that, you need to use the bool shouldRepaint(oldDelegate) function.
    When you return true this method re-render you’r drawing.

    So the best way for me to do this is something like this:

    
    class MyCustomPainter extends CustomPainter {
      const MyCustomPainter({Key? key, required this.addLine});
      final bool addLine;
    
      @override
      void paint(Canvas canvas, Size size) {
        const p1 = Offset(50, 50);
        const p2 = Offset(50, 300);
        const p3 = Offset(50, 50);
        const p4 = Offset(250, 50);
        const p5 = Offset(250, 50);
        const p6 = Offset(250, 150);
        const p7 = Offset(250, 150);
        const p8 = Offset(250, 300);
        final paint = Paint()
          ..color = Colors.black
          ..strokeWidth = 4
          ..strokeCap = StrokeCap.round;
        canvas.drawLine(p1, p2, paint);
        canvas.drawLine(p3, p4, paint);
        canvas.drawLine(p5, p6, paint);
        if (addLine) {
          canvas.drawLine(p7, p8, paint);
        }
      }
    
      @override
      bool shouldRepaint(MyCustomPainter oldDelegate) {
        return oldDelegate.addLine != this.addLine;
      }
    }
    

    and in your StatefulWidget something like this:

    
    bool addLine = false;
    
    @override
      void initState() {
        super.initState();
        Future.delayed(const Duration(seconds: 1), () {
          setState(() {
            addLine = true;
          });
        });
      }
    
    @override
      Widget build(BuildContext context) {
      ...
      CustomPaint(
                  painter: MyCustomPainter(addLine: addLine)
      )
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search