当前位置: 首页 > news >正文

flutter 画转盘

import 'package:flutter/material.dart';
import 'dart:math';const double spacingAngle = 45.0; // 每两个文字之间的角度
// 自定义绘制器,ArcTextPainter 用于在圆弧上绘制文字
class ArcTextPainter extends CustomPainter {final double rotationAngle; // 动画旋转角度final double strokeWidth; // 圆环的宽度final List<String> text; // 文字列表final double curIndex; // 当前旋转进度ArcTextPainter({required this.rotationAngle,required this.strokeWidth,required this.text,required this.curIndex,});@overridevoid paint(Canvas canvas, Size size) {final radius = size.width / 2; // 圆的半径final center = Offset(size.width / 2, size.height / 2); // 圆心的坐标// 创建用于绘制圆弧的画笔final paint = Paint()..color = Colors.grey.shade300 // 圆弧的颜色..strokeWidth = strokeWidth // 圆弧的宽度..style = PaintingStyle.stroke; // 画笔样式为描边// 计算圆弧的矩形区域final arcRect = Rect.fromCircle(center: center, radius: radius - strokeWidth / 2);canvas.drawArc(arcRect, pi, pi, false, paint); // 绘制圆弧// 创建用于绘制箭头的画笔final arrowPaint = Paint()..color = Colors.purple // 箭头的颜色..style = PaintingStyle.fill; // 画笔样式为填充// 定义箭头的路径final arrowPath = Path();arrowPath.moveTo(center.dx, center.dy - radius + strokeWidth / 2); // 箭头起点arrowPath.lineTo(center.dx - 10, center.dy - radius + strokeWidth / 2 + 20); // 箭头的左边arrowPath.lineTo(center.dx + 10, center.dy - radius + strokeWidth / 2 + 20); // 箭头的右边arrowPath.close(); // 结束路径canvas.drawPath(arrowPath, arrowPaint); // 绘制箭头// 绘制圆弧上的文字_drawTextAlongArc(canvas, center, radius - strokeWidth / 2);}// 在圆弧上绘制文字void _drawTextAlongArc(Canvas canvas, Offset center, double radius) {final textPainter = TextPainter(textAlign: TextAlign.center, // 文字对齐方式为居中textDirection: TextDirection.ltr, // 文字方向为从左到右);// 遍历所有文字并绘制for (int i = 0; i < text.length; i++) {// 计算当前文字的角度double angle = (i - curIndex) * spacingAngle * (pi / 180) - pi/2;// print("angle:${i} ${angle*180/pi}");// 检查文字是否在可视范围内if (angle >= -pi && angle <= 0) {// 计算文字的位置final x = center.dx + radius * cos(angle); // x 坐标final y = center.dy + radius * sin(angle); // y 坐标canvas.save(); // 保存当前画布状态canvas.translate(x, y); // 移动画布到文字的位置// 设置文字的样式和内容textPainter.text = TextSpan(text: text[i],style: TextStyle(fontSize: 14, color: Colors.black), // 文字的样式);textPainter.layout(); // 计算文字的大小// 计算文字的实际可见区域double visibleFraction = _calculateVisibleFraction(angle);if (visibleFraction < 1.0) {// 如果文字不完全可见,则应用裁剪遮罩canvas.clipRect(Rect.fromLTWH(-textPainter.width / 2, // 左上角 x 坐标-textPainter.height / 2, // 左上角 y 坐标textPainter.width, // 文字的宽度textPainter.height, // 文字的高度));}textPainter.paint(canvas, Offset(-textPainter.width / 2, -textPainter.height / 2)); // 绘制文字canvas.restore(); // 恢复画布状态}}}// 计算文字的可见比例double _calculateVisibleFraction(double angle) {// 文字显示的比例,确保在 [-pi, 0] 范围内显示完全if (angle < -pi / 2) {return max(0, (angle + pi) / (pi / 2)); // 文字被遮挡的部分} else if (angle > 0) {return max(0, (-angle) / (pi / 2)); // 文字被遮挡的部分}return 1.0; // 文字完全可见}@overridebool shouldRepaint(CustomPainter oldDelegate) => true; // 是否需要重新绘制
}// ArcTextExample 是一个示例 widget,用于展示自定义绘制的效果
class ArcTextExample extends StatefulWidget {final double strokeWidth; // 圆环的宽度final List<String> text; // 文字列表final int initialIndex; // 初始索引final double animationDuration; // 动画持续时间const ArcTextExample({Key? key,required this.strokeWidth,required this.text,required this.initialIndex,required this.animationDuration,}) : super(key: key);@override_ArcTextExampleState createState() => _ArcTextExampleState();
}class _ArcTextExampleState extends State<ArcTextExample>with SingleTickerProviderStateMixin {late AnimationController _controller; // 动画控制器late Animation<double> _animation; // 动画double curIndex = 0.0; // 保存当前旋转的进度bool isAnimating = false; // 标记动画是否正在进行final TextEditingController indexController = TextEditingController(); // 目标索引的文本控制器final TextEditingController durationController = TextEditingController(); // 动画持续时间的文本控制器@overridevoid initState() {super.initState();// 初始化文本控制器的值indexController.text = widget.initialIndex.toString();durationController.text = widget.animationDuration.toString();// 计算初始旋转角度double initialAngle = ( - widget.initialIndex ) * spacingAngle * (pi / 180) - pi / 2;curIndex = widget.initialIndex.toDouble(); // 初始化时 curIndex 是初始索引// 创建动画控制器_controller = AnimationController(duration: Duration(seconds: widget.animationDuration.toInt()), // 设置动画的持续时间vsync: this, // 与当前的 TickerProvider 绑定);// print("initialAngle: ${initialAngle*180/pi}");// 创建动画_animation = Tween<double>(begin: initialAngle, // 动画开始的角度end: initialAngle + 2 * pi, // 动画结束的角度).animate(_controller)..addListener(() {setState(() {print("_animation.value:  ${_animation.value * 180 / pi}");// 更新当前角度对应的索引范curIndex = (-(_animation.value + pi / 2) * (180 / pi)) / spacingAngle;print("Current Index: ${curIndex.toStringAsFixed(2)}"); // 打印当前索引});});}@overridevoid dispose() {_controller.dispose(); // 释放动画控制器资源indexController.dispose(); // 释放目标索引的文本控制器资源durationController.dispose(); // 释放动画持续时间的文本控制器资源super.dispose();}// 旋转到目标索引void rotateToIndex(int targetIndex, double duration) {if(targetIndex != curIndex){setState(() {if (isAnimating) {// 如果正在进行动画,则停止并重置_controller.stop();isAnimating = false;}_controller.duration = Duration(seconds: duration.toInt()); // 设置动画的持续时间double startAngle = (-curIndex) * spacingAngle * (pi / 180) - pi / 2; // 使用当前索引角度作为起始角度double targetAngle = (-targetIndex) * spacingAngle * (pi / 180) - pi / 2;  // 计算目标角度print("开始度数: ${startAngle * 180/pi} 结束度数:${targetAngle * 180/pi}");double endAngle;// 确定旋转方1if (targetAngle < 0) {// 顺时针旋转endAngle = startAngle + targetAngle;} else {// 逆时针旋转endAngle = startAngle - targetAngle;}_animation = Tween<double>(begin: startAngle, // 动画开始的角度end: targetAngle, // 动画结束的角度).animate(_controller);isAnimating = true; // 标记动画为进行中_controller.reset(); // 重置动画控制_controller.forward(); // 开始动画});}}@overrideWidget build(BuildContext context) {return Scaffold(body: Column(children: [SizedBox(height: 140), // 上部间距Center(child: CustomPaint(size: Size(300, 200), // 设置圆弧的大小painter: ArcTextPainter(rotationAngle: _animation.value, // 当前旋转角度strokeWidth: widget.strokeWidth, // 圆环的宽度text: widget.text, // 文字列表curIndex: curIndex, // 当前旋转进度),),),SizedBox(height: 20), // 下部间距Padding(padding: const EdgeInsets.symmetric(horizontal: 20.0), // 水平内边距child: Column(children: [// 目标索引的输入框TextField(controller: indexController,decoration: InputDecoration(labelText: 'Target Index', // 输入框标签),keyboardType: TextInputType.number, // 键盘类型为数字),// 动画持续时间的输入框TextField(controller: durationController,decoration: InputDecoration(labelText: 'Animation Duration (seconds)', // 输入框标签),keyboardType: TextInputType.number, // 键盘类型为数字),SizedBox(height: 20), // 输入框和按钮之间的间距// 旋转按钮ElevatedButton(onPressed: () {// 获取目标索引和动画持续时间int targetIndex = int.tryParse(indexController.text) ?? 0;double duration = double.tryParse(durationController.text) ?? 10.0;// if (isAnimating) {//   // 如果动画正在进行,停止并保存当前进度//   _controller.stop();//   curIndex = (-(_animation.value + pi / 2) * (180 / pi)) / spacingAngle; // 保存当前进度为 curIndex//   _controller.reset(); // 重置动画控制器// }// 旋转到目标索引rotateToIndex(targetIndex, duration);},child: Text('Rotate to Index'), // 按钮文本),],),),],),);}
}void main() {runApp(MaterialApp(home: ArcTextExample(strokeWidth: 100.0, // 圆环的宽度text: List.generate(11, (i) => '第$i层'), // 文字列表initialIndex: 3, // 初animationDuration: 10.0, // 默认动画时间为10秒),));
}

​​​​​​​

相关文章:

flutter 画转盘

import package:flutter/material.dart; import dart:math;const double spacingAngle 45.0; // 每两个文字之间的角度 // 自定义绘制器&#xff0c;ArcTextPainter 用于在圆弧上绘制文字 class ArcTextPainter extends CustomPainter {final double rotationAngle; // 动画旋…...

图像识别,图片线条检测

import cv2 import numpy as np # 读取图片 img cv2.imread(1.png)# 灰度化 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 边缘检测 edges cv2.Canny(gray, 100, 200) 当某个像素点的梯度强度低于 threshold1 时&#xff0c;该像素点被认为是非边缘&#xff1b;当梯度强度…...

python crawler web page

npm install or pip install 插件 import json import time from openpyxl import load_workbook from pip._vendor import requests from bs4 import BeautifulSoup import pandas as pd import re import xlsxwriter 設置request header header {user-agent: Mozilla/5.0…...

基于QT实现的TCP连接的网络通信(客户端)

上篇介绍了QT实现网络通信的服务器端&#xff0c;还没看服务器的朋友们先去上篇了解&#xff0c;这篇我来实现一下客户端的实现。 首先还是新建一个项目 选择mainwindow类 在通信前将.pro文件的第一行代码中追加network 窗口搭建 在mainwindow.ui中完成一下窗口的搭建 首先在…...

Vue2中watch与Vue3中watch对比

上一节说到了 computed计算属性对比 &#xff0c;虽然计算属性在大多数情况下更合适&#xff0c;但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法&#xff0c;来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时&#…...

Web 3 一些常见术语

目录 Provider 提供者Signer 签名者Transaction 交易Contract 合约Receipt 收据 首先&#xff0c;从高层次上对可用对象的类型及其负责的内容有一个基本的了解是很有用的。 Provider 提供者 一个 Provider 是与区块链的只读连接&#xff0c;允许查询区块链状态&#xff0c;例…...

揭开数据分析中的规范性分析:从入门到精通

目录 引言1. 规范性分析的基本概念2. 规范性分析的方法论2.1 线性规划&#xff1a;资源利用最大化2.2 决策树分析&#xff1a;直观的选择路径2.3 贝叶斯网络&#xff1a;应对不确定性的利器2.4 多目标优化&#xff1a;平衡多重目标的艺术 3. 规范性分析的实际应用3.1 商业决策中…...

Linux文件IO

目录 前言 一.文件操作 系统调用接口 1.打开文件 2.关闭文件 3.读取文件 4.写入文件 二.文件描述符 重定向 三.动静态库 前言 在Linux操作系统中&#xff0c;文件I/O是一个核心概念&#xff0c;涉及如何读写文件、与设备通信以及如何管理数据流。Linux下一切皆文件, …...

ccfcsp-202309(1、2、3)

202309-1 坐标变换&#xff08;其一&#xff09; #include <bits/stdc.h> using namespace std; int main() {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int n, m;cin >> n >> m;int x, y;int opx 0, opy 0;for(int i 0; i < n; i){cin &g…...

数据结构--数据结构概述

一、数据结构三要素 1. 数据的逻辑结构 数据的逻辑结构是指数据元素之间的关系和组织方式&#xff0c;通常分为线性结构和非线性结构。 线性结构&#xff1a;例如线性表&#xff0c;其中数据元素按照顺序排列&#xff0c;彼此之间存在一对一的关系。 非线性结构&#xff1a;…...

Spring中的BeanFactoryAware

BeanFactoryAware 是 Spring 框架中的一个接口&#xff0c;用于在 Spring 容器中获取 BeanFactory 实例。实现这个接口的类可以在其属性被设置后获取到 BeanFactory&#xff0c;从而可以访问 Spring 容器中的其他 bean。 BeanFactoryAware 接口概述 BeanFactoryAware 接口位于…...

Neo4j service is not installed

问题&#xff1a; Starting Neo4j. Neo4j service is not installed Unable to start. See user log for details. Run with --verbose for a more detailed error message.解决&#xff1a; neo4j windows-service install neo4j start ok了...

LeetCode 3132.找出与数组相加的整数 II:排序+3次尝试(nlog n)

【LetMeFly】3132.找出与数组相加的整数 II&#xff1a;排序3次尝试(nlog n) 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-the-integer-added-to-array-ii/ 给你两个整数数组 nums1 和 nums2。 从 nums1 中移除两个元素&#xff0c;并且所有其他元素都与变量…...

微信小程序--26(全局配置-1)

一、全局配置文件 1.标志 app.json 2.配置项 pages 记录当前小程序所有页面的存放路径 window 全局配置小程序窗口配置 tabBar 设置小程序底部的tabBar效果 style 是否启用新版本的组将样式 3.window 导航栏区域 navigationBar …...

汽车4S店管理系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设残哥 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目、 源…...

bug的常见排查和分析思路以及相关的原因分类

作为开发人员&#xff0c;经常会收到来自用户和QA&#xff0c;领导反馈的各种问题。 为了快速问题&#xff0c;我们有时需要站在更高的角度&#xff0c;更全面的看待问题。才能更快锁定问题。 具体的bug还需要结合企业实际业务情况&#xff0c;相关的框架&#xff0c;依赖库&…...

Nature:7个提升科研产出的实用建议

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 一个值得思考的问题是&#xff1a;层出不穷的效率工具到底是提升还是降低了科研产出&#xff1f; 大学教授萨拉 (Sara) 描述了她典型的工作日场景&#xff1a;"…...

react-native从入门到实战系列教程-页面之间的跳转

路由的跳转,是app开发中需要处理的问题,一个页面不可能装下那么多的内容。在react-native中,我们使用的路由组件跟reactjs中还是有区别的,这里贴出官网的文档:https://reactnavigation.org/docs/navigating 实现效果 安装 按照官网的指导安装即可。代码实现 app.jsx中改造…...

HarmonyOS应用开发者高级认证(一)

1、依次点击A、B、C、D四个按钮&#xff0c;其中不会触发UI刷新的是&#xff1a; 答案&#xff1a; Button("C").onClick(() > {this.nameList[0].name "Jim"})分析&#xff1a;直接更新非一级数据不会触发UI刷新 2、如果要实现Row组件内的子元素均匀…...

【网络】套接字(socket)编程——UDP版

1.socket 1.1.什么是socket Socket 的中文翻译过来就是“套接字”。 套接字是什么&#xff0c;我们先来看看它的英文含义&#xff1a;插座。 Socket 就像一个电话插座&#xff0c;负责连通两端的电话&#xff0c;进行点对点通信&#xff0c;让电话可以进行通信&#xff0c;端…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

探索Selenium:自动化测试的神奇钥匙

目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

sshd代码修改banner

sshd服务连接之后会收到字符串&#xff1a; SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢&#xff1f; 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头&#xff0c…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

C++--string的模拟实现

一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现&#xff0c;其目的是加强对string的底层了解&#xff0c;以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量&#xff0c;…...

起重机起升机构的安全装置有哪些?

起重机起升机构的安全装置是保障吊装作业安全的关键部件&#xff0c;主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理&#xff1a; 一、超载保护装置&#xff08;核心安全装置&#xff09; 1. 起重量限制器 功能&#xff1a;实时监测起升载荷&a…...

python基础语法Ⅰ

python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器&#xff0c;来进行一些算术…...

C++中vector类型的介绍和使用

文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…...