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

相关文章

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Pandas使用SQLite3实战

《Pandas使用SQLite3实战》本文主要介绍了Pandas使用SQLite3实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1 环境准备2 从 SQLite3VlfrWQzgt 读取数据到 DataFrame基础用法:读

Flutter打包APK的几种方式小结

《Flutter打包APK的几种方式小结》Flutter打包不同于RN,Flutter可以在AndroidStudio里编写Flutter代码并最终打包为APK,本篇主要阐述涉及到的几种打包方式,通... 目录前言1. android原生打包APK方式2. Flutter通过原生工程打包方式3. Futte

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

Python实战之屏幕录制功能的实现

《Python实战之屏幕录制功能的实现》屏幕录制,即屏幕捕获,是指将计算机屏幕上的活动记录下来,生成视频文件,本文主要为大家介绍了如何使用Python实现这一功能,希望对大家有所帮助... 目录屏幕录制原理图像捕获音频捕获编码压缩输出保存完整的屏幕录制工具高级功能实时预览增加水印多平台支持屏幕录制原理屏幕