美文网首页Flutter
flutter 绘制流水(水波上升)动态效果

flutter 绘制流水(水波上升)动态效果

作者: TryEnough | 来源:发表于2019-04-26 11:25 被阅读41次

    欢迎去浏览原文:http://tryenough.com/flutter-wave

    效果

    你可以先简单理解下贝塞尔曲线的原理:

    推荐这个关于贝塞尔的教程:http://www.html-js.com/article/1628

    代码:

    1.创建绘制波浪边界的代码

    创建一个基础的绘制类,可接收动画的x和y值:

    import 'package:flutter/material.dart';
    
    abstract class BasePainter extends CustomPainter{
      Animation<double> _xAnimation;
      Animation<double> _yAnimation;
    
      set XAnimation(Animation<double> value) {
        _xAnimation = value;
      }
    
      set YAnimation(Animation<double> value) {
        _yAnimation = value;
      }
    
      Animation<double> get YAnimation => _yAnimation;
    
      Animation<double> get XAnimation => _xAnimation;
    
    }
    

    实现

    欢迎去浏览原文:http://tryenough.com/flutter-wave

    import 'dart:math';
    
    import 'package:flutter_wave/painter_base.dart';
    import 'package:flutter/material.dart';
    
    class WavePainter extends BasePainter {
      int waveCount;
      int crestCount;
      double waveHeight;
      List<Color> waveColors;
      double circleWidth;
      Color circleColor;
      Color circleBackgroundColor;
      bool showProgressText;
      TextStyle textStyle;
    
      WavePainter(
          {this.waveCount = 1,
            this.crestCount = 2,
            this.waveHeight,
            this.waveColors,
            this.circleColor = Colors.grey,
            this.circleBackgroundColor = Colors.white,
            this.circleWidth = 5.0,
            this.showProgressText = true,
            this.textStyle = const TextStyle(
              fontSize: 60.0,
              color: Colors.blue,
              fontWeight: FontWeight.bold,
              shadows: [
                Shadow(color: Colors.grey, offset: Offset(5.0, 5.0), blurRadius: 5.0)
              ],
            )});
    
      @override
      void paint(Canvas canvas, Size size) {
        double width = size.width;
        double height = size.height;
    
        if (waveHeight == null) {
          waveHeight = height / 10;
          height = height + waveHeight;
        }
    
        if (waveColors == null) {
          waveColors = [
            Color.fromARGB(
                100, Colors.blue.red, Colors.blue.green, Colors.blue.blue)
          ];
        }
    
        Offset center = new Offset(width / 2, height / 2);
        double xMove = width * XAnimation.value;
        double yAnimValue = 0.0;
        if (YAnimation != null) {
          yAnimValue = YAnimation.value;
        }
        double yMove = height * (1.0 - yAnimValue);
        Offset waveCenter = new Offset(xMove, yMove);
    
        var paintCircle = new Paint()
          ..color = Colors.grey
          ..style = PaintingStyle.fill
          ..strokeWidth = circleWidth
          ..maskFilter = MaskFilter.blur(BlurStyle.inner, 5.0);
    
    //    canvas.drawCircle(center, min(width, height) / 2, paintCircle);
    
        List<Path> wavePaths = [];
    
        for (int index = 0; index < waveCount; index++) {
          double direction = pow(-1.0, index);
          Path path = new Path()
            ..moveTo(waveCenter.dx - width, waveCenter.dy)
            ..lineTo(waveCenter.dx - width, center.dy + height / 2)
            ..lineTo(waveCenter.dx + width, center.dy + height / 2)
            ..lineTo(waveCenter.dx + width, waveCenter.dy);
    
          for (int i = 0; i < 2; i++) {
            for (int j = 0; j < crestCount; j++) {
              double a = pow(-1.0, j);
              path
                  ..quadraticBezierTo(
                    waveCenter.dx +
                        width * (1 - i - (1 + 2 * j) / (2 * crestCount)),
                    waveCenter.dy + waveHeight * a * direction,
                    waveCenter.dx +
                        width * (1 - i - (2 + 2 * j) / (2 * crestCount)),
                    waveCenter.dy);
            }
          }
    
          path..close();
    
          wavePaths.add(path);
        }
        var paint = new Paint()
          ..color = circleBackgroundColor
          ..style = PaintingStyle.fill
          ..maskFilter = MaskFilter.blur(BlurStyle.inner, 5.0);
    
        canvas.saveLayer(
            Rect.fromCircle(center: center, radius: min(width, height) / 2), paint);
    
    //    canvas.drawCircle(center, min(width, height) / 2, paint);
    
        paint
    //      ..blendMode = BlendMode.srcATop
          ..style = PaintingStyle.fill
          ..strokeWidth = 2.0
          ..maskFilter = MaskFilter.blur(BlurStyle.inner, 10.0);
    
        for (int i = 0; i < wavePaths.length; i++) {
          if (waveColors.length >= wavePaths.length) {
            paint.color = waveColors[i];
          } else {
            paint.color = waveColors[0];
          }
          canvas.drawPath(wavePaths[i], paint);
        }
    //    paint.blendMode = BlendMode.srcATop;
        if (showProgressText) {
          TextPainter tp = TextPainter(
              text: TextSpan(
                  text: '${(yAnimValue * 100.0).toStringAsFixed(0)}%',
                  style: textStyle),
              textDirection: TextDirection.rtl)
            ..layout();
    
          tp.paint(
              canvas, Offset(center.dx - tp.width / 2, center.dy - tp.height / 2));
        }
        canvas.restore();
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) {
        return oldDelegate != this;
      }
    }
    
    

    欢迎去浏览原文:http://tryenough.com/flutter-wave

    2.创建工厂方法,用于创建波浪图形

    import 'package:flutter/material.dart';
    
    import 'package:flutter_wave/painter_base.dart';
    import 'package:flutter_wave/painter/painter_wave.dart';
    
    abstract class BasePainterFactory {
      BasePainter getPainter();
    }
    
    class WavePainterFactory extends BasePainterFactory {
      BasePainter getPainter() {
        return WavePainter(
          waveCount: 1,
          waveColors: [
            Colors.lightBlueAccent[200],
          ],
          textStyle:
          TextStyle(
            fontSize: 60.0,
            foreground: Paint()
              ..color = Colors.lightBlue
              ..style = PaintingStyle.fill
              ..strokeWidth = 2.0
              ..blendMode = BlendMode.difference
              ..colorFilter = ColorFilter.mode(Colors.white, BlendMode.exclusion)
              ..maskFilter = MaskFilter.blur(BlurStyle.solid, 1.0),
            fontWeight: FontWeight.bold,
          ),
        );
      }
    }
    
    

    给波浪添加动画

    推荐你先学一下动画基础知识:
    https://juejin.im/post/5b6270edf265da0f473539a6

    原理解释:

    xAnimation和yAnimation不断的从0到1变化,然后上面绘制波浪的地方根据这些值不断的进行绘制,形成动画。

    import 'package:flutter_wave/painter_factory.dart';
    import 'package:flutter/material.dart';
    
    class ProgressManager extends StatefulWidget {
      @override
      _ProgressManagerState createState() =>
          new _ProgressManagerState().._factory = WavePainterFactory();
    }
    
    class _ProgressManagerState extends State<ProgressManager>
        with TickerProviderStateMixin {
      AnimationController xController;
      AnimationController yController;
      Animation<double> xAnimation;
      Animation<double> yAnimation;
      List<double> _progressList = [];
      double curProgress = 0;
      BasePainterFactory _factory;
    
      set painter(BasePainterFactory factory) {
        _factory = factory;
      }
    
      setProgress(double progress) {
        _progressList.add(progress);
        onProgressChange();
      }
    
      onProgressChange() {
        if (_progressList.length > 0) {
          if (yController != null && yController.isAnimating) {
            return;
          }
          double nextProgress = _progressList[0];
          _progressList.removeAt(0);
          final double begin = curProgress;
          yController = new AnimationController(
              vsync: this, duration: Duration(milliseconds: 1000));
          yAnimation =
              new Tween(begin: begin, end: nextProgress).animate(yController);
          yAnimation.addListener(_onProgressChange);
          yAnimation.addStatusListener(_onProgressStatusChange);
          yController.forward();
        }
      }
    
      @override
      void initState() {
        super.initState();
        xController = new AnimationController(
            vsync: this, duration: Duration(milliseconds: 4000));
        xAnimation = new Tween(begin: 0.0, end: 1.0).animate(xController);
        xAnimation.addListener(_change);
        yController = new AnimationController(
            vsync: this, duration: Duration(milliseconds: 5000));
        yAnimation = new Tween(begin: 0.0, end: 1.0).animate(yController);
        yAnimation.addListener(_onProgressChange);
        yAnimation.addStatusListener(_onProgressStatusChange);
    
        doDelay(xController, 0);
    
        Future.delayed(Duration(milliseconds: 3000), () {
          setProgress(0.66);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child:
          Container(
            width: MediaQuery.of(context).size.width,
            height: 400.0,
            child: new CustomPaint(
              painter: _factory.getPainter()
                ..XAnimation = xAnimation
                ..YAnimation = yAnimation,
              size: new Size(MediaQuery.of(context).size.width, 400.0),
            ),
          ),
        );
      }
    
      void _change() {
        setState(() {});
      }
    
      void _onProgressChange() {
        setState(() {
          curProgress = yAnimation.value;
        });
      }
    
      void _onProgressStatusChange(status) {
        if (status == AnimationStatus.completed) {
          onProgressChange();
        }
      }
    
      void doDelay(AnimationController controller, int delay) async {
        Future.delayed(Duration(milliseconds: delay), () {
          controller..repeat();
        });
      }
    
      @override
      void dispose() {
        xController.dispose();
        yController.dispose();
        xAnimation.removeListener(_change);
        yAnimation.removeListener(_onProgressChange);
        yAnimation.removeStatusListener(_onProgressStatusChange);
        super.dispose();
      }
    }
    
    

    使用的地方

    body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                ProgressManager(),
              ],
            ),
          ),
    

    欢迎去浏览原文:http://tryenough.com/flutter-wave

    下载demo地址

    http://tryenough.com/flutter-wave

    相关文章

      网友评论

        本文标题:flutter 绘制流水(水波上升)动态效果

        本文链接:https://www.haomeiwen.com/subject/jutfnqtx.html