本文主要是介绍自定义View实战之仿雷达蜘蛛网实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
效果图预览
1. 分析
1. 绘制多边形
2. 连接多边形各顶点
3. 绘制多边形各个顶点的文字
4. 绘制每一块的刻度
5. 造一些假数据用于绘制数据区域
2. 技术实现原理
1. PathMeasure可以获取任意正多边形各个坐标的余弦值、正弦值
2. 连线闭合采用Path类实现
3. 绘制文字采用canvas自带的canvas.drawText方法 不过需要计算角度
4. 绘制刻度需要计算各个点的坐标 可以用PointF记录点的坐标
5. 文本内容的水平垂直居中处理
3. 初始化一些东西
SIDE_NUM代表边的数目即几边形,PathMeasure mMeasure的
mMeasure.setPath(mPath,true)方法为PathMeasure设置路径,
boolean getPosTan (float distance, float[] pos, float[] tan)
- distance为距离当前path起点的距离,取值范围为0到path的长度。
- pos 如果不为null,则返回path当前距离的位置坐标,pos[0] = x,pos[1] = y 。
- tan 如果不为null,则返回当前位置坐标的切线,tan[0] = x, tan[1] = y 。
- 返回值为boolean,true表示成功,数据会存入pas、tan,反之则为失败,数据也不会存入pas、tan。
mCosArray,mCosArray用来存放各个顶点的余弦和正弦值
//定义多边形顶点文字
private String[] mStrings = {“A”,”B”,”C”,”D”,”E”,”F”,”G”,”H”};
//定义多边形数据区域x坐标的数据
private float[] mValues = {10.0f,47.0f,11.0f,38.0f,9.0f,52.0f,14.0f,37.0f};
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);mCenterX = w / 2;mCenterY = h / 2;mPointF = new PointF();mLength = DensityUtil.dip2px(getContext(),120);mPath.addCircle(0,0,mLength, Path.Direction.CW);mMeasure.setPath(mPath,true);mPos = new float[2];mTan = new float[2];mCosArray = new float[SIDE_NUM];mSinArray = new float[SIDE_NUM];for (int i=0; i < SIDE_NUM; i++){mMeasure.getPosTan((float) (Math.PI * 2 * mLength * i / SIDE_NUM), mPos, mTan);mCosArray[i] = mTan[0];mSinArray[i] = mTan[1];}mPath.reset();
}
4. 绘制多边形和多边形连线
a. 绘制多边形
mPath.lineTo连接各个顶点 顶点坐标值=mLength*正弦和余弦值
POLYGON_NUM表示画多少个多边形 多边形从大往小画的
所以canvas.scale(1 - i / POLYGON_NUM,1 - i / POLYGON_NUM);这个代表缩放比例,每次画完一个多边形都需要闭合和重置mPath.close()和mPath.reset();
canvas.save()和canvas.restore()是保证这一次绘制过程对别的绘制不会有影响,因为这里操作了scale比例缩放
//绘制多边形
private void drawPolygon(Canvas canvas) {mPaint.setColor(Color.GRAY);for (int i = 0; i < POLYGON_NUM; i++){canvas.save();canvas.scale(1 - i / POLYGON_NUM,1 - i / POLYGON_NUM);mPath.moveTo(0,mLength);for (int j = 0; j < SIDE_NUM; j++){mPath.lineTo(mLength* mCosArray[j],mLength* mSinArray[j]);}mPath.close();canvas.drawPath(mPath,mPaint);mPath.reset();canvas.restore();}
}
b. 多边形连线
mPaint.setColor(Color.BLUE);加颜色区分
mPath.moveTo(0,0);每次都移动坐标点到原点
原点开始连接各个顶点
mPath.lineTo(mLength * mCosArray[j],mLength * mSinArray[j]);
//绘制多边形的连线private void drawPolygonLine(Canvas canvas) {mPaint.setColor(Color.BLUE);//连线for (int j=0; j< SIDE_NUM; j++){mPath.moveTo(0,0);mPath.lineTo(mLength * mCosArray[j],mLength * mSinArray[j]);drawPolygonText(canvas,j);}mPath.close();canvas.drawPath(mPath,mPaint);mPath.reset();}
5. 绘制多边形各顶点文字
canvas.rotate(180);旋转180的原因是我是从底部90度开始的,为了保证A-F顺时针旋转,所以旋转180度,根据cos值判断文字的方向 不一定说要以0.2判断 我不过取了一个相对值
//绘制多边形各顶点文字
private void drawPolygonText(Canvas canvas,int index) {canvas.save();canvas.rotate(180);mPointF.x = -mLength * mCosArray[index] * 1.1f;mPointF.y = -mLength * mSinArray[index] * 1.1f;//根据cos值,判断文字位置,设置居左、居中、居右if (mCosArray[index] > 0.2){textCenter(new String[]{mStrings[index]},mTextPaint,canvas,mPointF, Paint.Align.RIGHT);}else if (mCosArray[index] < -0.2){textCenter(new String[]{mStrings[index]},mTextPaint,canvas,mPointF, Paint.Align.LEFT);}else {textCenter(new String[]{mStrings[index]},mTextPaint,canvas,mPointF, Paint.Align.CENTER);}canvas.restore();
}/*** 多行文本居中、居右、居左* @param strings 文本字符串列表* @param point 点的坐标*/
protected void textCenter(String[] strings, Paint paint, Canvas canvas, PointF point, Paint.Align align){paint.setTextAlign(align);Paint.FontMetrics fontMetrics= paint.getFontMetrics();float top = fontMetrics.top;float bottom = fontMetrics.bottom;float ascent = fontMetrics.ascent;float descent = fontMetrics.descent;int length = strings.length;float total = (length - 1) * (-top + bottom) + (-ascent + descent);float offset = total / 2 - bottom;for (int i = 0; i < length; i++) {float yAxis = -(length - i - 1) * (-top + bottom) + offset;canvas.drawText(strings[i], point.x, point.y + yAxis, paint);}
}
6. 绘制刻度
mPointF.x: 计算每一个多边形顶点处的X坐标
mPointF.y:计算每一个多边形顶点处的Y坐标
//绘制刻度
private void drawPolygonScale(Canvas canvas) {canvas.save();canvas.rotate(180);DecimalFormat sdf = new DecimalFormat ("0");//外循环控制边数 每一个顶点处都绘制刻度for (int i = 0; i < SIDE_NUM; i++) {//内循环控制多边形数量 for (int j = 1; j < POLYGON_NUM; j++){mPointF.x = mLength * (1 - j / POLYGON_NUM) * mCosArray[i];mPointF.y = mLength * (1 - j / POLYGON_NUM) * mSinArray[i];String text = sdf.format(10 * (POLYGON_NUM - j));mScaleTextPaint.getTextBounds(text,0,text.length(),mScaleTextRect);canvas.drawText(text, mPointF.x - mScaleTextRect.width() / 2, mPointF.y + mScaleTextRect.height() / 2, mScaleTextPaint);}}//绘制中心点数字String centerValue = "0";mScaleTextPaint.getTextBounds(centerValue,0,centerValue.length(),mScaleTextRect);canvas.drawText(centerValue,0 - mScaleTextRect.width() / 2,0 + mScaleTextRect.height() / 2,mScaleTextPaint);canvas.restore();
}
7. 绘制数据区域
mValues定义一个x轴的数据点集合,然后根据一定比例计算相应的y轴的数据点集合,然后通过path连接各个坐标点
//绘制数据区域 连接各个数据点
private void drawPolygonData(Canvas canvas) {for (int i = 0; i < SIDE_NUM; i++){float value = mValues[i];float yValue = value * 6.18f;Log.e("drawGraph value",value+" ;yValue: "+yValue);if ( i == 0 ){mPath.moveTo(yValue * mCosArray[i], yValue * mSinArray[i]);}else {mPath.lineTo(yValue * mCosArray[i], yValue*mSinArray[i]);}}mPath.close();canvas.drawPath(mPath, mDataFillPaint);canvas.drawPath(mPath,mStrokePaint);mPath.reset();
}
8. 小结和源码下载
小结:
最核心的是通过PathMeasure类的getPosTan方法获得此任意正多边形各角坐标的余弦值、正弦值,
然后通过正弦余弦值获得各个点的x,y坐标值,还有就是Path类的使用以及canvas的旋转,缩放等操作,
别忘记canvas.save和canvas.restore不然会影响其他的绘制源码下载:最后统一提供下载地址
9.联系方式
QQ:1509815887
这篇关于自定义View实战之仿雷达蜘蛛网实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!