Flutter学习笔记:自定义View的实战(网状图)

2023-10-07 02:20

本文主要是介绍Flutter学习笔记:自定义View的实战(网状图),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言部分

这段时间陆续学习flutter框架,因为一直坚信跨平台开发会是下一次的变革,以前也接触过一些跨平台的框架,但是觉得都不太好用的,如RN,cordova等。RN我是写过一些demo的,但是发现调试和代码书写都很麻烦,后期就没有深入研究,Cordova的话是在项目中了解过,感觉入手有点难,因为Android开发对js了解过于少。因为我把一个Cordova的项目重写成原生项目,期间先是通过jsbridge做了过度。

这次flutter的出现让我觉得,跨平台又有了一种新的可能,所以特意学习,并写了一个小的项目练手。

项目地址

项目还没完善,有时间我会继续来做的。

在这里插入图片描述

内容部分

今天主题是介绍一下flutter中的自定义view,其实和Android很相似,所以我们写起来应该是很简单的,只不过就是flutter中的API还不是很全面,有一些东西还不能完全像做android一样实现,可能后期随着flutter的发展会越来越完善的。

  1. 首先我们想自定义view的话也需要继承一个类就是CustomPainter这个类就类似于android中的view了。

    class MyView extends CustomPainter{@overridevoid paint(Canvas canvas, Size size) {// TODO: implement paint}@overridebool shouldRepaint(CustomPainter oldDelegate) {// TODO: implement shouldRepaintreturn null;}
    }
    

    有没有和Android很类似的,其中的paint就类似于android中的onDraw和onMeasure了。

    shouldRepaint就是是否需要重新绘制的意思。一般的话直接写oldDelegate != this;就行了。就是原来的Widget和当前的不一致,就重新绘制。

  2. 其实后面的逻辑就和我们写android一样了,在paint进行绘制操作。

    @overridevoid paint(Canvas canvas, Size size) {viewCenterX = size.width / 2;viewCenterY = size.height / 2;if (viewCenterX > viewCenterY) {maxRadius = viewCenterY;} else {maxRadius = viewCenterX;}canvas.save();drawPolygon(canvas);drawMaskLayer(canvas);drawText(canvas);canvas.restore();}
    
  3. 绘制多边形的代码和以前的一样,主要用到了path来完成,并且path的用法和Android高度一致。代码如下:

    void drawPolygon(Canvas canvas) {///每个角的度数eachAngle = CIRCLE_ANGLE / sideNum;///找好所有的顶点,连接起来即可for (int i = 0; i < layerNum; i++) {mPath.reset();eachRadius = maxRadius / layerNum * (i + 1);for (int j = 0; j < sideNum + 1; j++) {if (j == 0) {mPath.moveTo(viewCenterX + eachRadius, viewCenterY);} else {double x = viewCenterX + eachRadius * cos(degToRad(eachAngle * j));double y = viewCenterY + eachRadius * sin(degToRad(eachAngle * j));mPath.lineTo(x, y);}}mPath.close();canvas.drawPath(mPath, mPaint);}//这个是把顶点连接起来。drawLineLinkPoint(canvas, eachAngle, eachRadius);}
    
  4. 绘制完成多边形后,再绘制上面的遮罩层,然后在完善一下就完成了。

后面其实都是常规操作了

不过要注意的有的方法flutter是不提供的,需要我们自己来实现,比如计算顶点坐标的时候,我们需要自己通过角度和斜边来计算x和y的坐标了。

 num degToRad(num deg) => deg * (pi / 180.0);num radToDeg(num rad) => rad * (180.0 / pi);
我贴一下完整的代码,就不上传demo了。
import 'dart:math';/// 自定义控件
import 'package:flutter/material.dart';class SpiderNetView extends CustomPainter {///多边形几个边int sideNum = 6;///默认几层多边形int layerNum = 6;///view 的中心点double viewCenterX;double viewCenterY;///半径,最大的半径double maxRadius;Paint mPaint;Path mPath;final double CIRCLE_ANGLE = 360;Paint mLayerPaint;SpiderNetView(int sideNum) {this.sideNum = sideNum;mPaint = new Paint();mPaint.color = randomRGB();mPaint.isAntiAlias = true;mPaint.style = PaintingStyle.stroke;mPath = new Path();mLayerPaint = new Paint();mLayerPaint.color = randomARGB();mLayerPaint.isAntiAlias = true;mLayerPaint.style = PaintingStyle.fill;}@overridevoid paint(Canvas canvas, Size size) {viewCenterX = size.width / 2;viewCenterY = size.height / 2;if (viewCenterX > viewCenterY) {maxRadius = viewCenterY;} else {maxRadius = viewCenterX;}canvas.save();drawPolygon(canvas);drawMaskLayer(canvas);drawText(canvas);canvas.restore();}@overridebool shouldRepaint(CustomPainter oldDelegate) {// TODO: implement shouldRepaintreturn oldDelegate != this;}double eachRadius;double eachAngle;void drawPolygon(Canvas canvas) {///每个角的度数eachAngle = CIRCLE_ANGLE / sideNum;///找好所有的顶点,连接起来即可for (int i = 0; i < layerNum; i++) {mPath.reset();eachRadius = maxRadius / layerNum * (i + 1);for (int j = 0; j < sideNum + 1; j++) {if (j == 0) {mPath.moveTo(viewCenterX + eachRadius, viewCenterY);} else {double x = viewCenterX + eachRadius * cos(degToRad(eachAngle * j));double y = viewCenterY + eachRadius * sin(degToRad(eachAngle * j));mPath.lineTo(x, y);}}mPath.close();canvas.drawPath(mPath, mPaint);}drawLineLinkPoint(canvas, eachAngle, eachRadius);}void drawLineLinkPoint(Canvas canvas, double eachAngle, double eachRadius) {mPath.reset();for (int i = 0; i < sideNum; i++) {mPath.moveTo(viewCenterX, viewCenterY);double x = viewCenterX + eachRadius * cos(degToRad(eachAngle * i));double y = viewCenterY + eachRadius * sin(degToRad(eachAngle * i));mPath.lineTo(x, y);mPath.close();canvas.drawPath(mPath, mPaint);}}void drawMaskLayer(Canvas canvas) {mPath.reset();for (int i = 0; i < sideNum; i++) {double mRandomInt = randomInt();double x =viewCenterX + maxRadius * cos(degToRad(eachAngle * i)) * mRandomInt;double y =viewCenterY + maxRadius * sin(degToRad(eachAngle * i)) * mRandomInt;if (i == 0) {mPath.moveTo(x, viewCenterY);} else {mPath.lineTo(x, y);}}mPath.close();canvas.drawPath(mPath, mLayerPaint);}void drawText(Canvas canvas) {for (int i = 0; i < sideNum; i++) {double x = viewCenterX + maxRadius * cos(degToRad(eachAngle * i));double y = viewCenterY + maxRadius * sin(degToRad(eachAngle * i));}}num degToRad(num deg) => deg * (pi / 180.0);num radToDeg(num rad) => rad * (180.0 / pi);Color randomRGB() {Random random = new Random();return Color.fromARGB(255, random.nextInt(255), random.nextInt(255), random.nextInt(255));}Color randomARGB() {Random random = new Random();return Color.fromARGB(random.nextInt(180), random.nextInt(255),random.nextInt(255), random.nextInt(255));}double randomInt() {Random random = new Random();return (random.nextInt(10) + 1) / 10;}
}

如果在android中是有直接可以使用的方法的。下面我贴一个我以前写的同样的一个demo,是使用Java代码来实现的。如下:

我用Java代码实现的网状图

结尾部分

flutter中的自定义view相对其他的跨平台来说更接近我们平时写的Java项目,这也是对我们android程序员的一个优势。我始终觉得跨平台是移动端的未来趋势,所以自己也会一直关注这方面的消息。

最后由于demo太大了,就不上传了。

这篇关于Flutter学习笔记:自定义View的实战(网状图)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/155431

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学