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{
      @override
      void paint(Canvas canvas, Size size) {
        // TODO: implement paint
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) {
        // TODO: implement shouldRepaint
        return null;
      }
    }
    

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

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

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

    @override
      void 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;
  }

  @override
  void 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();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return 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太大了,就不上传了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值