百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

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

bigegpt 2024-08-27 11:57 2 浏览

欢迎去浏览原文: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

相关推荐

10w qps缓存数据库——Redis(redis缓存调优)

一、Redis数据库介绍:Redis:非关系型缓存数据库nosql:非关系型数据库没有表,没有表与表之间的关系,更不存在外键存储数据的形式为key:values的形式c语言写的服务(监听端口),用来存...

Redis系列专题4--Redis配置参数详解

本文基于windowsX64,3.2.100版本讲解,不同版本默认配置参数不同在Redis中,Redis的根目录中有一个配置文件(redis.conf,windows下为redis.windows....

开源一夏 | 23 张图,4500 字从入门到精通解释 Redis

redis是目前出场率最高的NoSQL数据库,同时也是一个开源的数据结构存储系统,在缓存、数据库、消息处理等场景使用的非常多,本文瑞哥就带着大家用一篇文章入门这个强大的开源数据库——Redis。...

redis的简单与集群搭建(redis建立集群)

Redis是什么?是开源免费用c语言编写的单线程高性能的(key-value形式)内存数据库,基于内存运行并支持持久化的nosql数据库作用主要用来做缓存,单不仅仅是做缓存,比如:redis的计数器生...

推荐几个好用Redis图形化客户端工具

RedisPlushttps://gitee.com/MaxBill/RedisPlusRedisPlus是为Redis可视化管理开发的一款开源免费的桌面客户端软件,支持Windows、Linux...

关于Redis在windows上运行及fork函数问题

Redis在将数据库进行持久化操作时,需要fork一个进程,但是windows并不支持fork,导致在持久化操作期间,Redis必须阻塞所有的客户端直至持久化操作完成。微软的一些工程师花费时间在解决在...

你必须懂的Redis十大应用场景(redis常见应用场景)

Redis作为一款高性能的键值存储数据库,在互联网业务中有着广泛的应用。今天,我们就来详细盘点一下Redis的十大常用业务场景,并附上Golang的示例代码和简图,帮助大家更好地理解和应用Redis。...

极简Redis配置(redis的配置)

一、概述Redis的配置文件位于Redis安装目录下,文件名为redis.conf(Windows名为redis.windows.conf,linux下的是redis.conf)你可以通过C...

什么是redis,怎么启动及如何压测

从今天起咱们一起来学习一下关于“redis监控与调优”的内容。一、Redis介绍Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富。...

一款全新Redis UI可视化管理工具,支持WebUI和桌面——P3X Redis UI

介绍P3XRedisUI这是一个非常实用的RedisGUI,提供响应式WebUI访问或作为桌面应用程序使用,桌面端是跨平台的,而且完美支持中文界面。Githubhttps://github....

windows系统的服务器快速部署java项目环境地址

1、mysql:https://dev.mysql.com/downloads/mysql/(msi安装包)2、redis:https://github.com/tporadowski/redis/r...

window11 下 redis 下载与安装(windows安装redis客户端)

#热爱编程是一种怎样的体验#window11下redis下载与安装1)各个版本redis下载(windows)https://github.com/MicrosoftArchive/r...

一款轻量级的Redis客户端工具,贼好用!

使用命令行来操作Redis是一件非常麻烦的事情,我们一般会选用客户端工具来操作Redis。今天给大家分享一款好用的Redis客户端工具TinyRDM,它的界面清新又优雅,希望对大家有所帮助!简介Ti...

一个.NET开发且功能强大的Windows远程控制系统

我们致力于探索、分享和推荐最新的实用技术栈、开源项目、框架和实用工具。每天都有新鲜的开源资讯等待你的发现!项目介绍SiMayRemoteMonitorOS是一个基于Windows的远程控制系统,完...

Redis客户端工具详解(4款主流工具)

大家好,我是mikechen。Redis是大型架构的基石,也是大厂最爱考察内容,今天就给大家重点详解4款Redis工具@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集...