Flutter canvas 画一条波浪线 进度条

之前用 Flutter Canvas 画过一个三角三角形,html 的 Canvas 也画过一次类似的, 今天用 Flutter Canvas 试了下 感觉差不多:

html 版本

大致效果如下:

思路和 html 实现的类似:

也就是找出点的位置,使用二阶贝塞尔曲线实现:

 代码如下:
import 'package:flutter/material.dart';

class PageCanvas extends StatefulWidget {
  const PageCanvas({Key? key}) : super(key: key);

  @override
  State<PageCanvas> createState() => _PageCanvasState();
}

class _PageCanvasState extends State<PageCanvas> with TickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    controller = AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = Tween<double>(begin: 0, end: 1).animate(controller);
    controller.repeat();
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Scaffold(
      appBar: AppBar(
        title: const Text('Canvas'),
        backgroundColor: Colors.blue,
      ),
      body: Column(
        children: [
          AnimatedBuilder(
              animation: controller,
              builder: (context, widget) {
                return CustomPaint(
                  size: Size(size.width, size.height / 3),
                  painter: MyPainter(animation.value),
                );
              }),
          const SizedBox(
            height: 60,
          ),
          Center(
            child: SizedBox(
              // color: Colors.grey,
              width: 200,
              height: 200,
              child: ClipOval(
                child: Container(
                  color: Colors.grey.withOpacity(0.3),
                  child: AnimatedBuilder(
                      animation: controller,
                      builder: (context, widget) {
                        return CustomPaint(
                          size: Size(size.width, size.height / 3),
                          painter: MyPainter2(animation.value),
                        );
                      }),
                ),
              ),
            ),
          )
        ],
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    // TODO: implement dispose
    super.dispose();
  }
}

class MyPainter extends CustomPainter {
  final double value;
  const MyPainter(this.value);
  @override
  void paint(Canvas canvas, Size size) {
    // print(value);

    Paint paint = Paint();
    Path path = Path();

    double positionX = -size.width * value;
    double positionY = 100;
    double positionRange = 10;

    double positionX2 = -size.width * (1 - value);
    double positionY2 = 110;
    double positionRange2 = 20;

    double positionX3 = -size.width * (1.3 - value);
    double positionY3 = 120;
    double positionRange3 = 30;

    double step = size.width / 4;
    //
    path.moveTo(0 + positionX, positionY);
    for (int i = 1; i < 13; i++) {
      if (i % 2 == 1) {
        path.quadraticBezierTo(step * (2 * i - 1) + positionX,
            positionY - positionRange, step * (2 * i) + positionX, positionY);
      } else {
        path.quadraticBezierTo(step * (2 * i - 1) + positionX,
            positionY + positionRange, step * (2 * i) + positionX, positionY);
      }
    }

    path.lineTo(step * 10, 250);
    path.lineTo(0, 250);
    path.close();
    paint.color = Colors.blue.withOpacity(0.2);
    canvas.drawPath(path, paint);

    canvas.save();
    canvas.restore();

    path = Path();
    path.moveTo(0 + positionX2, positionY2);

    for (int i = 1; i < 13; i++) {
      if (i % 2 == 1) {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX2,
            positionY2 - positionRange2,
            step * (2 * i) + positionX2,
            positionY2);
      } else {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX2,
            positionY2 + positionRange2,
            step * (2 * i) + positionX2,
            positionY2);
      }
    }

    path.lineTo(step * 10, 250);
    path.lineTo(0, 250);
    path.close();
    paint.color = Colors.blue.withOpacity(0.6);
    canvas.drawPath(path, paint);

    canvas.save();
    canvas.restore();

    path = Path();
    path.moveTo(0 + positionX3, positionY3);

    for (int i = 1; i < 13; i++) {
      if (i % 2 == 1) {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX3,
            positionY3 - positionRange3,
            step * (2 * i) + positionX3,
            positionY3);
      } else {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX3,
            positionY3 + positionRange3,
            step * (2 * i) + positionX3,
            positionY3);
      }
    }

    path.lineTo(step * 10, 250);
    path.lineTo(0, 250);
    path.close();
    paint.color = Colors.blue;
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return oldDelegate != this;
    //return true;
  }
}

class MyPainter2 extends CustomPainter {
  final double value;
  const MyPainter2(this.value);
  @override
  void paint(Canvas canvas, Size size) {
    // print(value);

    Paint paint = Paint();
    Path path = Path();

    double positionX = -size.width * value;
    double positionY = 50;
    double positionRange = 10;

    double positionX2 = -size.width * (1 - value);
    double positionY2 = 60;
    double positionRange2 = 20;

    double positionX3 = -size.width * (1.3 - value);
    double positionY3 = 70;
    double positionRange3 = 30;

    double step = size.width / 4;
    //
    path.moveTo(0 + positionX, positionY);

    for (int i = 1; i < 13; i++) {
      if (i % 2 == 0) {
        path.quadraticBezierTo(step * (2 * i - 1) + positionX,
            positionY - positionRange, step * (2 * i) + positionX, positionY);
      } else {
        path.quadraticBezierTo(step * (2 * i - 1) + positionX,
            positionY + positionRange, step * (2 * i) + positionX, positionY);
      }
    }

    path.lineTo(step * 10, 250);
    path.lineTo(0, 250);
    path.close();
    paint.color = Colors.blue.withOpacity(0.2);
    canvas.drawPath(path, paint);

    canvas.save();
    canvas.restore();

    path = Path();
    path.moveTo(0 + positionX2, positionY2);

    for (int i = 1; i < 13; i++) {
      if (i % 2 == 0) {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX2,
            positionY2 - positionRange2,
            step * (2 * i) + positionX2,
            positionY2);
      } else {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX2,
            positionY2 + positionRange2,
            step * (2 * i) + positionX2,
            positionY2);
      }
    }

    path.lineTo(step * 10, 250);
    path.lineTo(0, 250);
    path.close();
    paint.color = Colors.blue.withOpacity(0.6);
    canvas.drawPath(path, paint);

    canvas.save();
    canvas.restore();

    path = Path();
    path.moveTo(0 + positionX3, positionY3);

    for (int i = 1; i < 13; i++) {
      if (i % 2 == 0) {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX3,
            positionY3 - positionRange2,
            step * (2 * i) + positionX3,
            positionY3);
      } else {
        path.quadraticBezierTo(
            step * (2 * i - 1) + positionX3,
            positionY3 + positionRange2,
            step * (2 * i) + positionX3,
            positionY3);
      }
    }

    path.lineTo(step * 10, 250);
    path.lineTo(0, 250);
    path.close();
    paint.color = Colors.blue;
    canvas.drawPath(path, paint);

    canvas.save();
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return oldDelegate != this;
    //return true;
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/360877.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

山东第四次文物普查启动,全面开展不可移动文物预防性保护

一、山东进行全面普查不可移动文物资源 近日&#xff0c;山东省政府下发了《关于做好第四次全国文物普查工作通知》&#xff0c;根据调查充分摸清山东不可移动文物资源状况。这是我国时隔16年再次启动文物普查&#xff0c;也是“十四五”期内最大的文物保护行动&#xff0c;以…

Memcached缓存服务器

目录 简介 NoSQL的优点和缺点 下面扩展一下关系型数据库和非关系型数据库的区别 Memcached 特点 原理 配置与安装 Memcached我们直接使用yum安装就可以了 安装后启动 修改配置文件 测试 开发端安装telnet 进行远程连接memcached&#xff0c;端口探测 以下显示为连接…

香蕉派BPI-M7 瑞芯微RK3588 人工智能开源硬件开发板公开发售

香蕉派(Banana Pi) BPI-M7瑞芯微K3588开源硬件单板计算机公开销售&#xff0c;支持WiFi 6和BT5.2&#xff0c;硬件有3个版本:8G Ram64G eMMC, 16G Ram128 eMMC和32G Ram128 eMMC 香蕉派BPI-M7采用睿芯最新旗舰RK3588八核64位处理器&#xff0c;最高频率为2.4GHz, 6 TOPS NPU&…

106.乐理基础-五线谱-八度记号

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;105.乐理基础-五线谱-谱号扩展-CSDN博客 上一个内容里的练习答案&#xff1a; 然后下图红圈位置的音&#xff0c;用高音谱号、低音谱号、中音谱号、次中音谱号&#xff0c;在加三根线的情况下无法表示&#xff0c;…

uniapp底部栏设置未读红点或角标

pages.json {... // 省略"tabBar": {"color": "#333333","selectedColor": "#3296fa","backgroundColor": "#ffffff","borderStyle": "white","list": [{"pagePat…

微信开放平台第三方授权(第四篇)-wechat发送客服消息

1.发送客服消息 上一张介绍了发送消息需要用到的authorizer_access_token,和发送消息的接口结合使用&#xff0c;上面直接上代码。 重写WechatMpService 获取token&#xff0c;这个发消息会用到 package com.test.wechat.service;import com.test.wechat.config.WechatMpConf…

Roxlabs全球IP代理服务:解锁高效数据采集与网络应用新境界

引言 在这个数字化迅速发展的时代&#xff0c;数据采集和网络应用的重要性显得愈发突出。江苏阿克索网络科技有限公司旗下的Roxlabs&#xff0c;以其卓越的全球IP代理服务&#xff0c;正引领着这一领域的创新和发展。Roxlabs不仅提供遍及200多个国家和地区的高质量动态住宅IP资…

10个最好的免费数据恢复软件工具分享【合集】

数据丢失经常发生。它可能是由于恶意软件、有缺陷的更新或疏忽造成的。无论哪种情况&#xff0c;这都是一个麻烦的事件。 许多人认为不可能恢复已删除的文件。这是一个错误的印象。 从回收站删除的文件很有可能仍然可以恢复。免费的开源数据恢复软件可以在这里为您提供帮助&a…

Linux下使用信号量实现PV操作

一.信号量与PV操作概述 在多道程序系统中&#xff0c;由于资源共享与进程合作&#xff0c;使各进程之间可能产生两种形式的制约关系&#xff0c;一种是间接相互制约&#xff0c;例如&#xff0c;在仅有一台打印机的系统&#xff0c;同一时刻只能有一个进程分配到到打印机&…

Python算法题集_最大子数组和

本文为Python算法题集之一的代码示例 题目53&#xff1a;最大子数组和 说明&#xff1a;给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。…

实战教程:使用Spring Boot和Vue.js开发社区团购管理系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

本地配置Joplin Server用于Joplin笔记同步并实现公网远程访问

文章目录 1. 安装Docker2. 自建Joplin服务器3. 搭建Joplin Sever4. 安装cpolar内网穿透5. 创建远程连接的固定公网地址 Joplin 是一个开源的笔记工具&#xff0c;拥有 Windows/macOS/Linux/iOS/Android/Terminal 版本的客户端。多端同步功能是笔记工具最重要的功能&#xff0c;…

关于JavaWeb的不使用模板创建方法

首先说一个特别重要的 , pom配置文件写完他不自动更新 就得这么办 , 不更新 idea就无法识别javaweb项目很烦

ASTORS国土安全奖:ManageEngine AD360荣获银奖

美国安全今日&#xff08;AST&#xff09;的年度“ASTORS”国土安全奖计划是一个备受瞩目的活动&#xff0c;致力于突显国土安全领域的创新与进步。这一奖项旨在表彰在保护国家免受安全威胁方面做出卓越贡献的个人和组织。该计划汇聚了执法、公共安全和行业领袖&#xff0c;不仅…

c4d线条放样模型的教程

c4d放样工具怎么使用&#xff1f;c4d中想要将线条放样成三维模型&#xff0c;该怎么放样呢&#xff1f;下面我们就来看看c4d线条放样模型的教程&#xff0c;需要的朋友可以参考下 c4d绘制的线条图形&#xff0c;想要放样成三维模型&#xff0c;该怎么放样呢&#xff1f;下面我…

谷歌上架防关联VPS开到和原来一样的IP造成关联?应该怎么选?

随着Google paly的发展&#xff0c;竞争越来越激烈&#xff0c;开发者们也面临的越来越多的挑战。其中&#xff0c;如何降低关联风险是开发者们重点关注的问题。 为了防止开发者账号的滥用或欺诈&#xff0c;谷歌会通过判断账号之间是否存在关联&#xff0c;并对违规账号进行处…

【Axure教程0基础入门】00Axure9汉化版下载、安装、汉化、注册+01制作线框图

写在前面&#xff1a;在哔哩哔哩上面找到的Axure自学教程0基础入门课程&#xff0c;播放量最高&#xff0c;5个多小时。课程主要分为4个部分&#xff0c;快速入门、动态面板、常用动效、项目设计。UP主账号【Song老师产品经理课堂】。做个有素质的白嫖er&#xff0c;一键三连必…

Qt QWidget Loading界面并覆盖在其他控件上面

目录 一、效果图二、Loading三、使用 一、效果图 界面中有一个Label&#xff0c;一个Button 点击Buttion&#xff0c;显示Loading的界面&#xff0c;并覆盖到Label和Button上面 二、Loading loadingwidget.h #ifndef LOADINGWIDGET_H #define LOADINGWIDGET_H#include <…

Python中类的相关术语(附带案例)

目录 1、面向对象 2、类 3、实例 4、初始化方法 5、魔法方法 6、字符串方法 7、self 8、数据、属性、操作、行为 9、父类、基类、超类 or 子类、派生类 10、多态 11、重载多态 and 重写多态 12、名称解释 1、面向对象 在Python中&#xff0c;面向对象编程&…

哪款洗地机好用?2024年洗地机推荐

家居清洁工作却是一项既重要又耗时的任务&#xff0c;尤其是地面的清扫工作&#xff0c;既要保证清洁&#xff0c;又要尽量减少对地板的磨损。吸拖一体的洗地机出现&#xff0c;让全职妈妈、忙碌的上班族以及健康状况欠佳的长者都能从繁重的家务活中解脱出来&#xff0c;享受自…