自定义首先接触到的时候觉得很有兴趣,便学习了一下
GcsSloop大神的自定义View教程也非常不错,覆盖前面且详细
学习完以上的教程后,还是需要自己动手来实践一下。
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//设置起始点
mStartX = event.getX();
mStartY = event.getY();
//清空原有的轨道
mMovePath.reset();
//移动到起始点
mMovePath.moveTo(mStartX, mStartY);
return true;
case MotionEvent.ACTION_MOVE:
final float endX = (mStartX + event.getX()) / 2;
final float endY = (mStartY + event.getY()) / 2;
//画出轨道曲线,quad是二次曲线
mMovePath.quadTo(mStartX, mStartY, endX, endY);
mStartX = event.getX();
mStartY = event.getY();
//重绘
invalidate();
return true;
}
return super.onTouchEvent(event);
}
然后在onDraw()中调用drawPath()即可。
private void drawMove(Canvas canvas) {
pathMeasure.setPath(mMovePath, false);
if (isMove) {
//计算图片的旋转角度,tan是当前点切线值,根据切线值计算角度
float degree = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI);
//旋转对应的角度
canvas.rotate(degree, pos[0], pos[1]);
//设置中心点在运行轨道上
mRect.set(pos[0] - mRectWidth, pos[1] - mRectWidth, pos[0] + mRectWidth, pos[1] + mRectWidth);
//绘制draw
if (mDrawable == null) {
canvas.drawRect(mRect, mCarPaint);
} else {
canvas.drawBitmap(mBitmap, null, mRect, mPaint);
}
}
}
具体参考Github:DiyViewPracticeDemo
雷达图的绘制我分为三部分,雷达网的绘制,覆盖区域的绘制,边界文字描述绘制
雷达网的绘制
/**
* 绘制雷达图。
*/
private void drawRader(Canvas canvas) {
radarPaint.setPathEffect(null);
float gap = radius / (dataCount - 1);
//雷达网的绘制
for (int i = 1; i < dataCount; i++) {
//不同环的半径,dataCount-1个环
float currentR = gap * i;
radarPath.reset();
for (int j = 0; j < dataCount; j++) {
//如果是0,也就移到右边的起始点
if (j == 0) {
radarPath.moveTo(centerX + currentR, centerY);
} else {
//其他情况得到60°,120°,180°,240°,300°的cos和sin值,利用cos值得到x轴坐标,sin值得到y轴坐标。
radarPath.lineTo((float) (centerX + currentR * Math.cos(angle * j)), (float) (centerY + currentR * Math.sin(angle * j)));
}
}
//闭合,终点连上起点
radarPath.close();
canvas.drawPath(radarPath, radarPaint);
}
//绘制中心到边界点的虚线
radarPaint.setPathEffect(dashPathEffect);
for (int i = 0; i < dataCount; i++) {
radarPath.reset();
radarPath.moveTo(centerX, centerY);
radarPath.lineTo((float) (centerX + radius * Math.cos(angle * i)), (float) (centerY + radius * Math.sin(angle * i)));
canvas.drawPath(radarPath, radarPaint);
}
}
覆盖区域绘制
//绘制覆盖区域
private void drawRegion(Canvas canvas) {
int sum = 0;
for (int i = 0; i < dataCount; i++) {
double percent = drawed[i] / MAX_Value;
sum += drawed[i];
//得到对应分值的对应的x,y坐标
float x = (float) (centerX + radius * Math.cos(angle * i) * percent);
float y = (float) (centerY + radius * Math.sin(angle * i) * percent);
//绘制过程同雷达网的绘制过程
if (i == 0) {
regionPath.moveTo(x, centerY);
} else {
regionPath.lineTo(x, y);
}
//为边界点绘制小圆点
canvas.drawCircle(x, y, 5, valuePaint);
}
//闭合
regionPath.close();
canvas.drawPath(regionPath, valuePaint);
valuePaint.setAlpha(255 / 2);
valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawPath(regionPath, valuePaint);
canvas.save();
String centerText = "能力值:%d";
canvas.drawText(String.format(Locale.getDefault(), centerText, sum), centerX - centerTextPaint.measureText(centerText) / 2, centerY, centerTextPaint);
canvas.restore();
}
边界文字描述绘制
//绘制边界点的文字描述
private void drawText(Canvas canvas) {
float fontBaseLine = fontMetrics.descent - fontMetrics.ascent;
for (int i = 0; i < dataCount; i++) {
//x,y也就是边界点的坐标
float x = (float) (centerX + (radius + fontBaseLine / 2) * Math.cos(angle * i));
float y = (float) (centerY + (radius + fontBaseLine / 2) * Math.sin(angle * i));
//位于左边的需要左移文字长度大小
if (angle * i >= 0 && angle * i < Math.PI / 2) {//0°<=角度<90°
canvas.drawText(strings[i], x, y, textPaint);
} else if (angle * i >= Math.PI / 2 && angle * i < Math.PI) {//90°<=角度<180°
float dis = textPaint.measureText(strings[i]);//文本长度
canvas.drawText(strings[i], x - dis, y, textPaint);
} else if (angle * i >= Math.PI && angle * i < 3 * Math.PI / 2) {//180°<=角度<270°
float dis = textPaint.measureText(strings[i]);//文本长度
canvas.drawText(strings[i], x - dis, y, textPaint);
} else if (angle * i >= 3 * Math.PI / 2 && angle * i < Math.PI * 2) {//270°<=角度<=360°
canvas.drawText(strings[i], x, y, textPaint);
}
}
}
具体参考Github:DiyViewPracticeDemo