本文主要是介绍Flutter学习笔记:自定义View的实战(网状图),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言部分
这段时间陆续学习flutter框架,因为一直坚信跨平台开发会是下一次的变革,以前也接触过一些跨平台的框架,但是觉得都不太好用的,如RN,cordova等。RN我是写过一些demo的,但是发现调试和代码书写都很麻烦,后期就没有深入研究,Cordova的话是在项目中了解过,感觉入手有点难,因为Android开发对js了解过于少。因为我把一个Cordova的项目重写成原生项目,期间先是通过jsbridge做了过度。
这次flutter的出现让我觉得,跨平台又有了一种新的可能,所以特意学习,并写了一个小的项目练手。
项目地址
项目还没完善,有时间我会继续来做的。
内容部分
今天主题是介绍一下flutter中的自定义view,其实和Android很相似,所以我们写起来应该是很简单的,只不过就是flutter中的API还不是很全面,有一些东西还不能完全像做android一样实现,可能后期随着flutter的发展会越来越完善的。
-
首先我们想自定义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和当前的不一致,就重新绘制。
-
其实后面的逻辑就和我们写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();}
-
绘制多边形的代码和以前的一样,主要用到了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);}
-
绘制完成多边形后,再绘制上面的遮罩层,然后在完善一下就完成了。
后面其实都是常规操作了
不过要注意的有的方法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的实战(网状图)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!