先讲一下我的目的,动手之前得想好我想要一个什么东西,先看下掌盟的是个什么样
这是由多个多边形组成的,很明显边长数我们不能固定死,因为每次的需求都是不同的
知道我们想要一个什么东西之后,在想想实现步骤,把复杂的功能化成简单的功能,就觉得不会麻烦了。一步一步来,首先画最外面的多边形——画里面的多边形——画顶点到中心点的线(外切圆半径)——在外切圆半径上取值,得到点坐标——将各个点连接起来就完成了。先不考虑里面颜色变化 ,先只画线
接下来该考虑怎么画这个多边形了,我们不可能用drawline的方式来画,只能用path,对比其中的方法也只有lineto可以了,好了接下来考虑的就是该从哪里开始画了。我想到有两条思路,
第一先指定一个点然后指定一个角度指定边长可以计算出下一个点的位置,一以此类推
第二就是先指定中心点的位置然后指定外切圆半径,取外切圆上的一点开始绘制
这两个方法应该是差不多的,我是用的第一种方法实现的。
ok,我们来讲一下第一种方法,先指定第一个点,我当时第一反应就是这个点一定要是多边形的最靠上的一个顶点,然后再仔细想一想,多边形肯定不能超过view的边界,所以指定一个最高点就不怕超过上边界,然后这个点肯定要在view宽度的最中间,所以不管怎么样,先写这样一句肯定没错
Rect mRect = new Rect(getLeft(),getTop(),getRight(),getBottom());
那么第一个点的位置出来了,
startY为什么不能直接是top,getTextHeight()很明显是文字的高度,因为在顶点上还要写文字的啊,我们先把它空间留出来。这个以后再说。
如图B点左边确定了,要画BC线还得知道A的角度和边长,A的角度好说,我们就认定x轴为外切圆在点B的切线,那么
角A=90-内角/2;
边长应该咋设置初始长度?
borderLength = Math.min(measuredHeight, measuredWidth)/2;
很明显无论怎么设置都有可能小了或者大了,之后会说怎么适配不让多边形出边界
C的坐标计算我就不说了
难的就是怎么算下一个点的坐标,要计算下一个点的坐标就必须高清楚偏转角度的变化规律,请看下图
角a和角c是一样大的,那么d就是增加的角度,初中就知道对角是相等的,所以增长的角度=180-内角
在看D点,角f就是C点的偏移角,h是增加的偏移角度,所以这个增长的角度公式是对的
那么当前偏移角=180-内角+上个点的偏移角
private void drawBorder(Canvas canvas,float x,float y){
float startX = x;
float startY = y;
float startAngle = this.startAngle;
Path mPath = new Path();
mPath.moveTo(startX,startY);
addPoint(startAngle,startX,startY);
for (int i = 0;i < borderNumber;i++){
if(i>0) startAngle += 180 - angleSingle;
float xMove = (float) (borderLength*Math.cos(getRadian(startAngle)));
float yMove = (float) (borderLength*Math.sin(getRadian(startAngle)));
float nextX = startX + xMove;
float nextY = startY + yMove;
mPath.lineTo(nextX,nextY);
if (i>0)addPoint(startAngle,startX,startY);
startY = nextY;
startX = nextX;
if(startX > mRect.right - getTextHeight() -10 || startY > mRect.bottom - getTextHeight() - 10 || startX < mRect.left + getTextHeight() + 10){
borderLength -= 10;
invalidate();
return;
}
}
mPath.lineTo(x,y);
canvas.drawPath(mPath, mLinePaint);
}
addPoint(startAngle,startX,startY);用来记录每个顶点的坐标和偏转角度
private void addPoint(float angle,float x,float y){
if (mPoints == null )return;
Vertex vertex = new Vertex();
vertex.setAngle(angle);
vertex.setX(x);
vertex.setY(y);
mPoints.add(vertex);
}
if(startX > mRect.right - getTextHeight() -10 || startY > mRect.bottom - getTextHeight() - 10 || startX < mRect.left + getTextHeight() + 10){这里是用来判断当前点是否超过了四边或者剩下的空间不足以用来写字了,如果超过了就将边长减小重新绘制。性能效率可根据实际情况调整
这样整个外多变形就画完了
有积分的需要源码的(1分意思一下谢谢)https://download.csdn.net/download/qq_24543821/10680545
另外Math.cos()sin()这方法里面的参数不是传的角度哦,是弧度,弧度计算方法
private float getRadian(float angle){
return (float) (Math.PI*angle/180);
}