Android高级进阶——自定义View实践篇(三)蜘蛛网评分控件实现原理

xiaoxiao2021-02-28  45

效果图如下: - 五边形

三角行

六边形

七边形

十二边形

这个效果其实并不是特别的难,只要知道了原理其实很简单

这里为了简单,数据都是直接写死的,有兴趣的可以把共有属性拿出来通过自定义属性来实现

难点

主要是怎么根据角度计算圆上的坐标,直接上代码

float centerX = 100f; // 已知圆心X坐标为100 float centerY = 100f; // 已知圆心Y坐标为100 float radius = 100f; // 已知半径为100 float angle = 45f; // 已知角度为45° double radians = Math.toRadians(angle); // 计算出弧度 float x = (float) (centerX + Math.sin(radians) * radius); // 计算出X坐标 float y = (float) (centerY - Math.cos(radians) * radius); // 计算出Y坐标

知道了圆上坐标的获取后就比较简单了,我们一步一步开始来吧

一、绘制蜘蛛网

我们先把各个层次的圆绘制出来,先从圆上整理思路:

for (int i = 1; i <= angleCount; i++) { canvas.drawCircle(spiderX,spiderY,hierarchy*i,spiderPaint); }

既然每层的圆已经出来了,那就简单了 我们只需要根据角度去计算圆上的坐标不就行了,然后通过 Path 将各个点组合绘制就OK了

绘制网

float nextRadians; //下个角的度数 总是相加 float spiderStartX; //x 坐标 float spiderStartY; //角度坐标 float nextHierarchy; //下一个圆的半径 最大为 radius for (int i = 1; i <= angleCount; i++) { canvas.drawCircle(spiderX, spiderY, hierarchy * i, spiderPaint); //重置路径 spiderPath.reset(); for (int j = 1; j <= angleCount; j++) { // //绘制蜘蛛网需要使用到的数据 nextHierarchy = hierarchy * i; //每层圆的半径 nextRadians = (float) (radians * j); //每个角的角度 spiderStartX = (float) (spiderX + Math.sin(nextRadians) * nextHierarchy); //圆上的坐标 x spiderStartY = (float) (spiderY - Math.cos(nextRadians) * nextHierarchy); //圆上的坐标 y if (j == 1) { //j == 1 时确定path 的起始点 spiderPath.moveTo(spiderStartX, spiderStartY); } else { spiderPath.lineTo(spiderStartX, spiderStartY); } } // //绘制蜘蛛网 spiderPath.close(); canvas.drawPath(spiderPath, spiderPaint);

是不是很简单,网绘制完成之后就会绘制各个点到圆心的连接线了,这个更简单:

连接线的绘制

只需要加入一个判断就OK

if (i == angleCount) { linePath.reset(); linePath.moveTo(spiderX, spiderY); linePath.lineTo(spiderStartX, spiderStartY); //绘制点到圆点的直线 canvas.drawPath(linePath, spiderPaint); }

这段代码的位置是在 内循环中执行的,别放错位置了噢!!

接下来就是绘制分数了,分数的绘制原理和网的绘制原理是一样的,只不过分数我们需要根据比例计算一下:

绘制分数

//分数 scorePath = new Path(); int maxScore = 10; Random random = new Random(); score = new float[angleCount]; //各个点的分数 for (int i = 0; i < angleCount; i++) { score[i] = random.nextInt(10 + 1); } //绘制相关逻辑,后面会给出完整代码 float nextRadians; //下个角的度数 总是相加 float spiderStartX; //x 坐标 float spiderStartY; //角度坐标 float scoreStartX; float scoreStartY; float nextHierarchy; //下一个圆的半径 最大为 radius for (int i = 1; i <= angleCount; i++) { canvas.drawCircle(spiderX, spiderY, hierarchy * i, spiderPaint); spiderPath.reset(); scorePath.reset(); for (int j = 1; j <= angleCount; j++) { //绘制蜘蛛网需要使用到的数据 nextHierarchy = hierarchy * i; //每层圆的半径 nextRadians = (float) (radians * j); //每个角的角度 spiderStartX = (float) (spiderX + Math.sin(nextRadians) * nextHierarchy); //圆上的坐标 x spiderStartY = (float) (spiderY - Math.cos(nextRadians) * nextHierarchy); //圆上的坐标 y // //绘制分数需要使用到的数据 nextRadians = (float) (radians * j); //计算该分数占总半径的比例值 nextHierarchy = nextHierarchy * score[j - 1] / maxScore; // scoreStartX = (float) (spiderX + Math.sin(nextRadians) * nextHierarchy); scoreStartY = (float) (spiderY - Math.cos(nextRadians) * nextHierarchy); if (i == angleCount) { linePath.reset(); linePath.moveTo(spiderX, spiderY); linePath.lineTo(spiderStartX, spiderStartY); //绘制点到圆点的直线 canvas.drawPath(linePath, spiderPaint); // //绘制分数区域 if (j == 1) { scorePath.moveTo(scoreStartX, scoreStartY); } else { scorePath.lineTo(scoreStartX, scoreStartY); } } if (j == 1) { //j == 1 时确定path 的起始点 spiderPath.moveTo(spiderStartX, spiderStartY); } else { spiderPath.lineTo(spiderStartX, spiderStartY); } } //绘制蜘蛛网 spiderPath.close(); canvas.drawPath(spiderPath, spiderPaint); // //绘制分数 scorePath.close(); canvas.drawPath(scorePath, scorePaint);

然后就很随意的实现了,是不是很神奇,我们把绘制圆的操作去掉,就变成了文章开头那样的效果了

下面给出完整代码:

package com.summary.hecom.custom.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import com.summary.hecom.R; import java.util.Random; /** * Created by hecom on 2018/5/2. */ public class SpiderWebScoreView extends View { private final Context mContext; private float spiderX; private float spiderY; private float radius; private int angleCount = 5; //蜘蛛网角的个数 private float angle; //每个角的角度 private double radians; //弧度度数 private float hierarchy; //层与层之间的间隔 private Paint spiderPaint; private Paint scorePaint; private Path spiderPath; private Path scorePath; private Path linePath; private int maxScore = 10; private float[] score; private Paint textPaint; public SpiderWebScoreView(Context context) { this(context, null); } public SpiderWebScoreView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public SpiderWebScoreView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext = context; init(); } private void init() { //这里为了方便就直接写死了,可以通过自定义属性获取 //圆心 x 坐标 spiderX = 400f; //圆心 y 坐标 spiderY = 400f; //圆 半径 radius = 200f; setSpideData(); //蜘蛛网画笔 spiderPaint = new Paint(); spiderPaint.setColor(getResources().getColor(R.color.mediumslateblue)); spiderPaint.setStyle(Paint.Style.STROKE); spiderPaint.setStrokeWidth(2); //分数画笔 scorePaint = new Paint(); scorePaint.setColor(Color.parseColor("#80DAA520")); scorePaint.setStyle(Paint.Style.FILL_AND_STROKE); textPaint = new Paint(); textPaint.setColor(Color.RED); textPaint.setTextSize(50); textPaint.setStyle(Paint.Style.STROKE); //蜘蛛网路径 spiderPath = new Path(); //各个点到圆心的连接线 linePath = new Path(); //分数 scorePath = new Path(); Random random = new Random(); score = new float[angleCount]; //各个点的分数 for (int i = 0; i < angleCount; i++) { score[i] = random.nextInt(10 + 1); } } private void setSpideData() { angle = 360 / angleCount; //层与层之间的宽度 hierarchy = radius / angleCount; //每个角对应的弧度 radians = Math.toRadians(angle); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawSpider(canvas); } //绘制蜘蛛网 private void drawSpider(Canvas canvas) { float nextRadians; //下个角的度数 总是相加 float spiderStartX; //x 坐标 float spiderStartY; //角度坐标 float scoreStartX; float scoreStartY; float nextHierarchy; //下一个圆的半径 最大为 radius for (int i = 1; i <= angleCount; i++) { spiderPath.reset(); scorePath.reset(); for (int j = 1; j <= angleCount; j++) { //绘制蜘蛛网需要使用到的数据 nextHierarchy = hierarchy * i; //每层圆的半径 nextRadians = (float) (radians * j); //每个角的角度 spiderStartX = (float) (spiderX + Math.sin(nextRadians) * nextHierarchy); //圆上的坐标 x spiderStartY = (float) (spiderY - Math.cos(nextRadians) * nextHierarchy); //圆上的坐标 y // //绘制分数需要使用到的数据 nextRadians = (float) (radians * j); //计算该分数占总半径的比例值 nextHierarchy = nextHierarchy * score[j - 1] / maxScore; // scoreStartX = (float) (spiderX + Math.sin(nextRadians) * nextHierarchy); scoreStartY = (float) (spiderY - Math.cos(nextRadians) * nextHierarchy); if (i == angleCount) { linePath.reset(); linePath.moveTo(spiderX, spiderY); linePath.lineTo(spiderStartX, spiderStartY); //绘制点到圆点的直线 canvas.drawPath(linePath, spiderPaint); // //绘制分数区域 if (j == 1) { scorePath.moveTo(scoreStartX, scoreStartY); } else { scorePath.lineTo(scoreStartX, scoreStartY); } } if (j == 1) { //j == 1 时确定path 的起始点 spiderPath.moveTo(spiderStartX, spiderStartY); } else { spiderPath.lineTo(spiderStartX, spiderStartY); } } //绘制蜘蛛网 spiderPath.close(); canvas.drawPath(spiderPath, spiderPaint); // //绘制分数 scorePath.close(); canvas.drawPath(scorePath, scorePaint); } } }

完事…..

转载请注明原文地址: https://www.6miu.com/read-2623528.html

最新回复(0)