【CustomPainter】渐变圆环

news2024/9/20 15:56:40

说明

实现一个渐变圆环,起点位置为- π / 2

效果

在这里插入图片描述

源码

  • GradientCircularPainter1
class GradientCircularPainter1 extends CustomPainter {
  final double progress;

  GradientCircularPainter1(this.progress);

  
  void paint(Canvas canvas, Size size) {
    const double strokeWidth = 8;
    final center = size.center(Offset.zero);
    final radius = (size.width - 2 * strokeWidth) / 2;

    // 整个圆环的背景色:绘制灰色圆环填充剩余部分
    final bgPaint = Paint()
      ..color = Colors.grey.withOpacity(0.2)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      0.0,
      2 * pi,
      false,
      bgPaint,
    );

    // 渐变进度条
    final rect = Offset.zero & size;
    const gradient =
        SweepGradient(colors: [Color(0xff40A9FD), Color(0xFF7451FF)]);

    final paint = Paint()
      ..shader = gradient.createShader(rect)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;

    const startAngle = -pi / 2;
    final sweepAngle = (2 * pi) * progress;

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      startAngle,
      sweepAngle,
      false,
      paint,
    );
  }

  
  bool shouldRepaint(GradientCircularPainter1 oldDelegate) {
    return progress != oldDelegate.progress;
  }
}
  • GradientCircularPainter2
class GradientCircularPainter2 extends CustomPainter {
  final double progress;

  GradientCircularPainter2(this.progress);

  
  void paint(Canvas canvas, Size size) {
    const double strokeWidth = 8;
    final center = size.center(Offset.zero);
    final radius = (size.width - 2 * strokeWidth) / 2;

    // 整个圆环的背景色:绘制灰色圆环填充剩余部分
    final bgPaint = Paint()
      ..color = Colors.grey.withOpacity(0.2)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      0.0,
      2 * pi,
      false,
      bgPaint,
    );

    // 渐变进度条
    final rect = Offset.zero & size;
    const gradient =
        SweepGradient(colors: [Color(0xff40A9FD), Color(0xFF7451FF)]);

    final paint = Paint()
      ..shader = gradient.createShader(rect)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;

    // 💡关键:画布逆时针旋转90度
    canvas.save();
    canvas.translate(center.dx, center.dy);
    canvas.rotate(-pi / 2);
    canvas.translate(-center.dx, -center.dy);

    const startAngle = 0.0;
    final sweepAngle = (2 * pi) * progress;

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      startAngle,
      sweepAngle,
      false,
      paint,
    );

    canvas.restore();
  }

  
  bool shouldRepaint(GradientCircularPainter2 oldDelegate) =>
      progress != oldDelegate.progress;
}
  • GradientCircularPainter3
class GradientCircularPainter3 extends CustomPainter {
  final double progress;

  GradientCircularPainter3(this.progress);

  
  void paint(Canvas canvas, Size size) {
    const double strokeWidth = 8;
    final center = size.center(Offset.zero);
    final radius = (size.width - 2 * strokeWidth) / 2;

    // 整个圆环的背景色:绘制灰色圆环填充剩余部分
    final bgPaint = Paint()
      ..color = Colors.grey.withOpacity(0.2)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      0.0,
      2 * pi,
      false,
      bgPaint,
    );

    // 渐变进度条
    final rect = Offset.zero & size;
    // 💡关键:首尾颜色一致,更改stops
    const gradient = SweepGradient(
        colors: [Color(0xff40A9FD), Color(0xFF7451FF), Color(0xff40A9FD)],
        stops: [0.0, 0.5, 0.7],
        tileMode: TileMode.clamp);

    final paint = Paint()
      ..shader = gradient.createShader(rect)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;

    const startAngle = -pi / 2;
    final sweepAngle = (2 * pi) * progress;

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      startAngle,
      sweepAngle,
      false,
      paint,
    );
  }

  
  bool shouldRepaint(GradientCircularPainter3 oldDelegate) {
    return progress != oldDelegate.progress;
  }
}
  • UI渲染
Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const SizedBox(
              height: 20,
            ),
            // 不是想要的渐变效果
            CustomPaint(
              size: const Size(60, 60),
              painter: GradientCircularPainter1(0.8),
            ),
            const SizedBox(
              height: 20,
            ),
            // 可取
            CustomPaint(
              size: const Size(60, 60),
              painter: GradientCircularPainter2(0.8),
            ),
            const SizedBox(
              height: 20,
            ),
            // 可取
            CustomPaint(
              size: const Size(60, 60),
              painter: GradientCircularPainter3(0.8),
            ),
          ],
        ),
      )

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零基础到项目实战:Node.js版Selenium WebDriver教程

在当今数字化时代,Web应用程序的质量和性能至关重要。为了确保这些应用的可靠性,自动化测试成为一种不可或缺的工具。Selenium,作为自动化测试领域的瑰宝,为我们提供了无限可能。本教程将深入介绍Selenium,以及如何结合…

如何删除EXCELL文件中的空行?

1,选择某一列 2,点击《开始》《查找和选择》>《定位条件》,调出《定位条件》的选择框; 3,在定位条件选项框,选择《空值》; 4,找到变灰被选中的某一行,右击《删除》 5&…

配置管理之configmap

一 、云原生要素——配 置分离 ConfigMap:存储明文配置 Secret:存储密文、敏感配置、用户重要信息和密码 等。 配置更新直接同步容器,热加载,无需重启pod或者容 器;镜像和配置分离,可单独修改发布 二、ConfigMap 1.…

详细分析Pytorch中的register_buffer基本知识(附Demo)

目录 1. 基本知识2. Demo3. 与自动注册的差异3.1 torch.nn.Parameter3.2 自动注册子模块3.3 总结 1. 基本知识 register_buffer 是 PyTorch 中 torch.nn.Module 提供的一个方法,允许用户将某些张量注册为模块的一部分,但不会被视为可训练参数。这些张量…

2区“发稿大户”!SCISSCI双检,3天上线出版,在这里,不用担心创新性不足~

【SciencePub学术】眼瞅评职晋升最后期限就在眼前,小编今天就给大家带来了一本“百发百中”的救命神刊~ 01 期刊详情 【期刊简介】IF:2.0-3.0 JCR2区中科院4区 【出版社】MDPI出版社 【自引率】8.30% 【类别】医学 【INDEX】SCIE&SSCI在检 02…

es由一个集群迁移到另外一个集群es的数据迁移

迁移es的数据 改下index的索引 就可以了。 查询 用curl -u就可以查询了

[数据集][目标检测]不同颜色的安全帽检测数据集VOC+YOLO格式7574张5类别

重要说明:数据集里面有2/3是增强数据集,请仔细查看图片预览,确认符合要求在下载,分辨率均为640x640 数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件…

微店商品列表API接口实战指南

微店商品列表数据接口是一种允许开发者在其应用程序中调用微店店铺所有商品数据的 API 接口。通过这个接口,开发者可以获取到微店店铺内所有商品的信息,包括但不限于商品的 ID、标题、价格、库存、销量、详情描述、图片等。以下是对微店商品列表数据接口…

如何确保Java程序分发后不被篡改?使用JNI对Java程序进行安全校验

前言 众所周知,Java/Kotlin编译后会编译成smali,使用Jadx这类的反编译工具或者Hook工具就能很轻松的把我们的软件安全校验给破解了。 为了防止这种情况发生,我们一般会将核心代码使用C编写,然后使用JNI技术,使用Java…

TCP报文格式

RFC9293协议规范,规定的TCP格式如图1, 对比RFC793规定的格式,控制位从6bit变成了8bit 图1,图片来源:datatracker.ietf.org 图2为,可对照的中文版TCP格式,中文版参照的是RFC793 图2 重点…

htop 命令:系统状态监控

一、命令简介 ​htop ​是一个互动式的进程查看器,它是 top ​命令的增强版本,提供了更丰富的功能和更好的用户界面。htop ​显示了系统的实时进程和资源使用情况(比如 CPU 和 memory 占用情况),允许用户进行交互式操…

基于Ubuntu的ECS实例实现OSS反向代理

阿里云OSS的存储空间(Bucket)访问地址会随机变换,您可以通过在ECS实例上配置OSS的反向代理,实现通过固定IP地址访问OSS的存储空间。 背景信息 阿里云OSS通过Restful API方式对外提供服务。最终用户通过OSS默认域名或者绑定的自定…

掌握Spring Boot数据库集成:用JPA和Hibernate构建高效数据交互与版本控制

在现代应用开发中,数据库操作是核心环节之一。Spring Boot提供了简化数据库集成的强大工具,而JPA(Java Persistence API)和Hibernate是两种非常流行的ORM(对象关系映射)框架,可以帮助我们将对象…

CLI示例(V2R8至V2R19C00版本):直连二层组网直接转发【AP+上层网络,增加AP下行口有线接入】

CLI示例(V2R8至V2R19C00版本):直连二层组网直接转发【AP+上层网络,增加AP下行口有线接入】 适用于:V200R008至V200R019C00版本的AC,以及有空闲以太网口的AP。 说明:本示例基于“直连二层组网直接转发【AP+AC+出口网关】”场景来介绍如何增加AP下行口有线接入。 业务需求…

Vue使用代理方式解决跨域问题

1、解决跨域问题 如果 Vue 前端应用请求后端 API 服务器,出现跨域问题(CORS),如下图: 解决方法:在 Vue 项目中,打开 vue.config.js 配置文件,在配置文件中使用代理解决跨域问题。 …

怎么找到抖音爆款内容,进行扩散传播?

企业如果想做好抖音平台的品牌营销,需要时刻监测抖音爆款内容并进行加热放大,据此快速创新和改进内容,才能短期提高品牌相关内容的曝光量,快速拉升品牌声量。怎么去找到抖音的爆款内容或者是值得品牌关注的优质内容,主…

印尼有几百种语言,初学者要怎么开始学习?《印尼语翻译通》app或许可以帮助你!印尼语零基础入门学习。

快速翻译,准确高效 采用最新技术,提供精准翻译。翻译结果符合中国人习惯。 体验印尼文化 学习地道印尼语,贴近当地文化。 旅游和工作的好帮手 提供旅游和商务用语,沟通无障碍。 学习印尼语的良师 文本和语音翻译,…

Spark-RDD持久化

一、Spark的三种持久化机制 1、cache 它是persist的一种简化方式,作用是将RDD缓存到内存中,以便后续快速访问,提高计算效率。cache操作是懒执行的,即执行action算子时才会触发。 2、persist 它提供了不同的存储级别&#xff0…

解锁数字转型新纪元:Vatee万腾平台,您的智能加速与策略智库

在数字经济时代的大潮中,企业的数字化转型已不再是选择题,而是必答题。面对这一挑战,Vatee万腾平台以其卓越的技术实力和前瞻性的战略视野,成为了众多企业加速数字化转型、实现智能化升级的得力助手和智囊团。 加速转型&#xff…

人工智能时代:程序员如何在变革中保持核心竞争力?

随着人工智能生成内容(AIGC)领域的快速发展,大语言模型如ChatGPT、Midjourney、Claude等层出不穷,AI辅助编程工具迅速普及,程序员的工作方式正在经历翻天覆地的变革。面对这一趋势,有人担心AI可能取代部分编…