Home > Back-end >  Adding a line to the drawing after a few seconds in flutter
Adding a line to the drawing after a few seconds in flutter

Time:12-01

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

CodePudding user response:

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,
                ),
        ],
    );
  }
}

CodePudding user response:

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)
  )
}
  • Related