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

前端 未结 2 1383
温柔的废话
温柔的废话 2020-12-06 08:52

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

相关标签:
2条回答
  • 2020-12-06 09:10

    use a custom CustomPainter class that passes Animation to the super constructor - that way the CustomPainter#paint() method is automagically called on each "frame" of the animation:

    class MyCustomPainter extends CustomPainter {
      List points;
      Paint linePaint;
      Animation anim;
      Size size = Size.zero;
    
      MyCustomPainter(Animation anim) : super(repaint: anim) {
        linePaint = Paint()
          ..style = PaintingStyle.stroke
          ..color = Colors.red
          ..strokeCap = StrokeCap.round
          ..strokeWidth = 16;
        this.anim = anim;
      }
    
      @override
      void paint(Canvas canvas, Size size) {
        if (size != this.size) {
          print('new size $size');
          this.size = size;
          Rect r = (Offset.zero & size).deflate(linePaint.strokeWidth * 1.5);
          points = [
            [r.topLeft, r.bottomLeft], // begins
            [r.bottomLeft, r.topRight], // ends
          ].map((o) => anim.drive(Tween(begin: o[0], end: o[1]))).toList();
        }
        canvas.drawLine(points[0].value, points[1].value, linePaint);
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) => true;
    }
    

    the complete working code would look like this:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(AnimatedPainterTest());
    }
    
    class AnimatedPainterTest extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(),
            body: Builder(
              builder: (BuildContext context) {
                AnimationController controller = AnimationController(
                  duration: Duration(milliseconds: 500),
                  vsync: Scaffold.of(context),
                );
                return Column(
                  children: <Widget>[
                    RaisedButton(
                      onPressed: () => controller.forward(from: 0.0),
                      child: Text('press me to start the animation'),
                    ),
                    Expanded(
                      child: SizedBox.expand(
                        child: CustomPaint(
                          painter: MyCustomPainter(controller),
                        ),
                      ),
                    )
                  ],
                );
              },
            ),
          ),
        );
      }
    }
    

    and the result is:

    0 讨论(0)
  • 2020-12-06 09:22

    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 :

    0 讨论(0)
提交回复
热议问题