【问题标题】:How to show a line being drawn from one point to another?如何显示从一个点到另一个点的线?
【发布时间】:2019-01-19 19:20:25
【问题描述】:

我使用 canvas.drawLine 来显示一条线,但我希望用户能够看到它从一个点绘制到另一个点,并且如果可能的话,还可以控制动画的持续时间。 (类似于进度条,但这是我的自定义小部件)

【问题讨论】:

    标签: flutter line paint


    【解决方案1】:

    使用自定义的CustomPainter 类,将Animation 传递给super 构造函数 - 这样CustomPainter#paint() 方法就会在动画的每个“帧”上自动调用:

    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;
    }
    

    完整的工作代码如下所示:

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

    结果是:

    【讨论】:

      【解决方案2】:

      您可以使用AnimationController 来控制动画持续时间。

      要“逐步”绘制线,您可以使用Tween(开始值和结束值之间的线性插值)。

      然后你只需要在你调用canvas.drawLine时将当前进度传递给你的画线器并计算每个paint()的新宽度/高度。

      工作示例:

      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;
        }
      }
      

      然后像这样使用它:

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

      线将在 3 秒内从0,0200,200 的大小框中绘制。

      结果:

      【讨论】:

      • 感谢您的 cmets @pskink,我已将 Line 设为小部件,但这当然不是强制性的。我不是 Flutter 专家,我提出了 a 解决方案,也许它没有使用最少的代码,但我认为它可以理解,易于阅读且高效。如果您认为它可以改进我的答案并对社区有益,请随时发布另一个答案:)
      • 如果他/她认为你的答案更好,用户仍然可以在之后更改接受的答案。
      • 太棒了!谢谢你的回答!
      猜你喜欢
      • 1970-01-01
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-23
      • 2019-12-28
      • 1970-01-01
      • 2021-10-08
      相关资源
      最近更新 更多