Search code examples
flutterlinepaint

How to show a line being drawn from one point to another?


I used canvas.drawLine to show a line but I want user to be able to see it being drawn from one point to another and also, if possible, control the duration of the animation. (something like progress bar but this is my custom widget)


Solution

  • You can use an AnimationController to control the animation duration.

    To draw the line "step by step" you can use a Tween (linear interpolation between a beginning and ending value).

    Then you just need to pass the current progress to your line painter and calculate the new width/height on each paint() when you call canvas.drawLine.

    Working example :

    import 'package:flutter/material.dart';
    
    class Line extends StatefulWidget {
      @override
      State<StatefulWidget> createState() => _LineState();
    }
    
    class _LineState extends State<Line> with SingleTickerProviderStateMixin {
      double _progress = 0.0;
      Animation<double> animation;
    
      @override
      void initState() {
        super.initState();
        var controller = AnimationController(duration: Duration(milliseconds: 3000), vsync: this);
    
        animation = Tween(begin: 1.0, end: 0.0).animate(controller)
          ..addListener(() {
            setState(() {
              _progress = animation.value;
            });
          });
    
        controller.forward();
      }
    
      @override
      Widget build(BuildContext context) {
        return CustomPaint(painter: LinePainter(_progress));
      }
    }
    
    class LinePainter extends CustomPainter {
      Paint _paint;
      double _progress;
    
      LinePainter(this._progress) {
        _paint = Paint()
          ..color = Colors.green
          ..strokeWidth = 8.0;
      }
    
      @override
      void paint(Canvas canvas, Size size) {
        canvas.drawLine(Offset(0.0, 0.0), Offset(size.width - size.width * _progress, size.height - size.height * _progress), _paint);
      }
    
      @override
      bool shouldRepaint(LinePainter oldDelegate) {
        return oldDelegate._progress != _progress;
      }
    }
    

    Then use it like this :

    import 'package:flutter/material.dart';
    
    class Home extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return _HomeState();
      }
    }
    
    class _HomeState extends State<Home> {
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: AppBar(
            title: Text('Line animation'),
            leading: new Icon(Icons.insert_emoticon),
          ),
          backgroundColor: Colors.white,
          body: SizedBox(height: 200, width: 200, child: Line()),
        );
      }
    }
    

    The line will be drawn in the sized box from 0,0 to 200,200 in 3 seconds.

    Result :

    enter image description here