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

相关文章

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

PowerShell中15个提升运维效率关键命令实战指南

《PowerShell中15个提升运维效率关键命令实战指南》作为网络安全专业人员的必备技能,PowerShell在系统管理、日志分析、威胁检测和自动化响应方面展现出强大能力,下面我们就来看看15个提升... 目录一、PowerShell在网络安全中的战略价值二、网络安全关键场景命令实战1. 系统安全基线核查

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

Java MQTT实战应用

《JavaMQTT实战应用》本文详解MQTT协议,涵盖其发布/订阅机制、低功耗高效特性、三种服务质量等级(QoS0/1/2),以及客户端、代理、主题的核心概念,最后提供Linux部署教程、Sprin... 目录一、MQTT协议二、MQTT优点三、三种服务质量等级四、客户端、代理、主题1. 客户端(Clien

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

MySQL中的索引结构和分类实战案例详解

《MySQL中的索引结构和分类实战案例详解》本文详解MySQL索引结构与分类,涵盖B树、B+树、哈希及全文索引,分析其原理与优劣势,并结合实战案例探讨创建、管理及优化技巧,助力提升查询性能,感兴趣的朋... 目录一、索引概述1.1 索引的定义与作用1.2 索引的基本原理二、索引结构详解2.1 B树索引2.2