一.自定义雷达图
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import android.graphics.Path; import java.util.ArrayList; import java.util.List; /** * Created by ${qc} on 2018/12/18. * 雷达图 */ public class CustomRadarView extends View { //数据个数 private int count = 5; //成绩圆点半径 private int valueRadius = 8; //网格最大半径 private float radius; //中心X private float centerX; //中心Y private float centerY; //雷达区画笔 private Paint mainPaint; //文本画笔 private Paint textPaint; //数据区画笔 private Paint valuePaint; //标题文字 private Listtitles; //各维度分值 private List data; //数据最大值 private double maxValue = 100; //弧度 private float angle; public CustomRadarView(Context context) { this(context, null); } public CustomRadarView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CustomRadarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { //雷达区画笔初始化 mainPaint = new Paint(); mainPaint.setColor(Color.parseColor("#4DB6AC")); mainPaint.setAntiAlias(true); mainPaint.setStrokeWidth(1); mainPaint.setStyle(Paint.Style.STROKE); //文本画笔初始化 textPaint = new Paint(); textPaint.setColor(Color.BLACK); textPaint.setTextAlign(Paint.Align.CENTER); textPaint.setTextSize(30); textPaint.setStrokeWidth(1); textPaint.setAntiAlias(true); //数据区(分数)画笔初始化 valuePaint = new Paint(); valuePaint.setColor(Color.parseColor("#4DB6AC")); valuePaint.setAntiAlias(true); valuePaint.setStyle(Paint.Style.FILL); //默认的title titles = new ArrayList<>(); titles.add("语法"); titles.add("听力"); titles.add("口语"); titles.add("写作"); titles.add("阅读理解"); count = titles.size(); //默认分数 data = new ArrayList<>(count); data.add(100.0); data.add(80.0); data.add(90.0); data.add(70.0); data.add(60.0); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { radius = Math.min(w, h) / 2 * 0.8f; centerX = w / 2; centerY = h / 2; //一旦size发生改变,重新绘制 postInvalidate(); super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { drawPolygon(canvas);//绘制蜘蛛网 drawLines(canvas);//绘制直线 drawTitle(canvas);//绘制标题 drawRegion(canvas);//绘制覆盖区域 } /** * 绘制多边形 * * @param canvas */ private void drawPolygon(Canvas canvas) { Path path = new Path(); //1度=1*PI/180 360度=2*PI 那么我们每旋转一次的角度为2*PI/内角个数 //中心与相邻两个内角相连的夹角角度 angle = (float) (2 * Math.PI / count); //每个蛛丝之间的间距 float r = radius / (count - 1); for (int i = 0; i < count; i++) { //当前半径 float curR = r * i; path.reset(); for (int j = 0; j < count; j++) { if (j == 0) { float x = (float) (centerX + curR * Math.sin(angle)); float y = (float) (centerY - curR * Math.cos(angle)); path.moveTo(x, y); } else { //根据半径,计算出蜘蛛丝上每个点的坐标 float x1 = (float) (centerX + curR * Math.sin(angle / 2)); float y1 = (float) (centerY + curR * Math.cos(angle / 2)); path.lineTo(x1, y1); float x2 = (float) (centerX - curR * Math.sin(angle / 2)); float y2 = (float) (centerY + curR * Math.cos(angle / 2)); path.lineTo(x2, y2); float x3 = (float) (centerX - curR * Math.sin(angle)); float y3 = (float) (centerY - curR * Math.cos(angle)); path.lineTo(x3, y3); float x4 = centerX; float y4 = centerY - curR; path.lineTo(x4, y4); float x = (float) (centerX + curR * Math.sin(angle)); float y = (float) (centerY - curR * Math.cos(angle)); path.lineTo(x, y); } } path.close(); canvas.drawPath(path, mainPaint); } } /** * 绘制直线 */ private void drawLines(Canvas canvas) { Path path = new Path(); path.reset(); //直线1 path.moveTo(centerX, centerY); float x1 = (float) (centerX + radius * Math.sin(angle)); float y1 = (float) (centerY - radius * Math.cos(angle)); path.lineTo(x1, y1); //直线2 path.moveTo(centerX, centerY); float x2 = (float) (centerX + radius * Math.sin(angle / 2)); float y2 = (float) (centerY + radius * Math.cos(angle / 2)); path.lineTo(x2, y2); //直线3 path.moveTo(centerX, centerY); float x3 = (float) (centerX - radius * Math.sin(angle / 2)); float y3 = (float) (centerY + radius * Math.cos(angle / 2)); path.lineTo(x3, y3); //直线4 path.moveTo(centerX, centerY); float x4 = (float) (centerX - radius * Math.sin(angle)); float y4 = (float) (centerY - radius * Math.cos(angle)); path.lineTo(x4, y4); //直线5 path.moveTo(centerX, centerY); float x5 = (float) (centerX); float y5 = (float) (centerY - radius); path.lineTo(x5, y5); path.close(); canvas.drawPath(path, mainPaint); } /** * 绘制标题文字 * * @param canvas */ private void drawTitle(Canvas canvas) { if (count != titles.size()) { return; } Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); float fontHeight = fontMetrics.descent - fontMetrics.ascent;//标题高度 //绘制文字1 float x1 = centerX; float y1 = centerY - radius; canvas.drawText(titles.get(0), x1, y1 - fontHeight / 5, textPaint); //绘制文字2 float x2 = (float) (centerX + radius * Math.sin(angle)); float y2 = (float) (centerY - radius * Math.cos(angle)); float dis = textPaint.measureText(titles.get(1));//标题一半的宽度 canvas.drawText(titles.get(1), x2 + dis, y2 + fontHeight / 5, textPaint); //绘制文字3 float x3 = (float) (centerX + radius * Math.sin(angle / 2)); float y3 = (float) (centerY + radius * Math.cos(angle / 2)); canvas.drawText(titles.get(2), x3, y3 + fontHeight, textPaint); //绘制文字4 float x4 = (float) (centerX - radius * Math.sin(angle / 2)); float y4 = (float) (centerY + radius * Math.cos(angle / 2)); canvas.drawText(titles.get(3), x4, y4 + fontHeight, textPaint); //绘制文字5 float x5 = (float) (centerX - radius * Math.sin(angle)); float y5 = (float) (centerY - radius * Math.cos(angle)); float dis5 = textPaint.measureText(titles.get(1));//标题的宽度 canvas.drawText(titles.get(4), x5 - dis5, y5 - fontHeight / 5, textPaint); } /** * 绘制覆盖区域 */ private void drawRegion(Canvas canvas) { valuePaint.setAlpha(255); Path path = new Path(); double dataValue; double percent; //绘制圆点1 dataValue = data.get(0); if (dataValue != maxValue) { percent = dataValue / maxValue; } else { percent = 1; } float x1 = centerX; float y1 = (float) (centerY - radius * percent); path.moveTo(x1, y1); canvas.drawCircle(x1, y1, valueRadius, valuePaint); //绘制圆点2 dataValue = data.get(1); if (dataValue != maxValue) { percent = dataValue / maxValue; } else { percent = 1; } float x2 = (float) (centerX + radius * percent * Math.sin(angle)); float y2 = (float) (centerY - radius * percent * Math.cos(angle)); path.lineTo(x2, y2); canvas.drawCircle(x2, y2, valueRadius, valuePaint); //绘制圆点3 dataValue = data.get(2); if (dataValue != maxValue) { percent = dataValue / maxValue; } else { percent = 1; } float x3 = (float) (centerX + radius * percent * Math.sin(angle / 2)); float y3 = (float) (centerY + radius * percent * Math.cos(angle / 2)); path.lineTo(x3, y3); canvas.drawCircle(x3, y3, valueRadius, valuePaint); //绘制圆点4 dataValue = data.get(3); if (dataValue != maxValue) { percent = dataValue / maxValue; } else { percent = 1; } float x4 = (float) (centerX - radius * percent * Math.sin(angle / 2)); float y4 = (float) (centerY + radius * percent * Math.cos(angle / 2)); path.lineTo(x4, y4); canvas.drawCircle(x4, y4, valueRadius, valuePaint); //绘制圆点5 dataValue = data.get(3); if (dataValue != maxValue) { percent = dataValue / maxValue; } else { percent = 1; } float x5 = (float) (centerX - radius * percent * Math.sin(angle)); float y5 = (float) (centerY - radius * percent * Math.cos(angle)); path.lineTo(x5, y5); canvas.drawCircle(x5, y5, valueRadius, valuePaint); path.close(); valuePaint.setStyle(Paint.Style.STROKE); //绘制覆盖区域外的连线 canvas.drawPath(path, valuePaint); //填充覆盖区域 valuePaint.setAlpha(128); valuePaint.setStyle(Paint.Style.FILL); canvas.drawPath(path, valuePaint); } //设置蜘蛛网颜色 public void setMainPaint(Paint mainPaint) { this.mainPaint = mainPaint; postInvalidate(); } //设置标题颜色 public void setTextPaint(Paint textPaint) { this.textPaint = textPaint; } //设置覆盖局域颜色 public void setValuePaint(Paint valuePaint) { this.valuePaint = valuePaint; postInvalidate(); } //设置各门得分 public void setData(List data) { this.data = data; postInvalidate(); } //设置各门title public void setValueTitle(List dataTitle){ this.titles = dataTitle; postInvalidate(); } //设置满分分数,默认是100分满分 public void setMaxValue(float maxValue) { this.maxValue = maxValue; } }
二.自定义水平柱状图
import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.graphics.Path; import java.util.List; /** * Created by ${qc} on 2018/12/18. * 横向的条形统计图 */ public class HorizontalChartView extends View{ /** * 最大值 */ private float maxValue; /** * 统计项目 */ private ListbarList; /** * 线的宽度 */ private int lineStrokeWidth; /** * 统计条宽度 */ private int barWidth; /** * 两条统计图之间空间 */ private int barSpace; /** * 各画笔 */ private Paint barPaint, linePaint, textPaint, scoreTextPaint; /** * 矩形区域 */ private Rect barRect, topRect; private Path textPath; private int itemNameWidth; private int scoreTextHeight; /** * 项目名和条形图之间的距离 */ private int betweenMargin; public HorizontalChartView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } /** * 初始化设置 */ private void init(Context context) { barPaint = new Paint(); barPaint.setColor(getResources().getColor(R.color.blue)); linePaint = new Paint(); linePaint.setColor(getResources().getColor(R.color.black)); lineStrokeWidth = DensityUtil.dip2px(context, 0.5f); linePaint.setStrokeWidth(lineStrokeWidth); textPaint = new Paint(); textPaint.setColor(getResources().getColor(R.color.black)); textPaint.setTextSize(DensityUtil.dip2px(context, 13)); textPaint.setAntiAlias(true); scoreTextPaint = new Paint(); scoreTextPaint.setTextSize(DensityUtil.dip2px(context, 13)); scoreTextPaint.setColor(getResources().getColor(R.color.white)); barRect = new Rect(0, 0, 0, 0); textPath = new Path(); barWidth = DensityUtil.dip2px(context, 18); barSpace = DensityUtil.dip2px(context, 20); scoreTextHeight = DensityUtil.dip2px(context, 13); itemNameWidth = DensityUtil.dip2px(context, 86); betweenMargin = scoreTextHeight / 2; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float lineViewWidth = (float) ((this.getWidth() - itemNameWidth) * 0.8);//线的宽度占总宽度的0.8,剩余的部分显示分数 float scoreWidth = lineViewWidth / 5; int scoreAdd = (int) (maxValue / 5); if (isInEditMode()) { return; } for (int i = 0; i < barList.size(); i++) { barRect.left = itemNameWidth; barRect.top = barSpace * (i + 2) + barWidth * i; barRect.right = (int) (lineViewWidth * (barList.get(i).getScore() / maxValue)) + itemNameWidth; barRect.bottom = barRect.top + barWidth; if ((barList.get(i).getScore() / maxValue) >= 0.6) { barPaint.setColor(getResources().getColor(R.color.blue)); } else { barPaint.setColor(getResources().getColor(R.color.red)); } canvas.drawRect(barRect, barPaint); canvas.drawText(barList.get(i).getScore() + "分", barRect.right, barRect.bottom - (barWidth - scoreTextHeight), textPaint); canvas.drawText(barList.get(i).getItemName(), itemNameWidth - betweenMargin - textPaint.measureText(barList.get(i).getItemName()), barRect.bottom - (barWidth - scoreTextHeight), textPaint); // canvas.drawText(String.valueOf(scoreAdd * (i + 1)), itemNameWidth + scoreWidth * (i + 1) - textPaint.measureText(String.valueOf(scoreAdd * (i + 1))) / 2, barSpace, textPaint); } // canvas.drawLine(itemNameWidth, 0, itemNameWidth, this.getHeight(), linePaint); } /** * 设置统计项目列表 * * @param barList */ public void setBarList(List barList) { this.barList = barList; if (barList == null) { throw new RuntimeException("BarChartView.setItems(): the param items cannot be null."); } if (barList.size() == 0) { return; } maxValue = barList.get(0).getScore(); for (BarBean bar : barList) { if (bar.getScore() > maxValue) { maxValue = bar.getScore(); } } invalidate(); } public static class BarBean{ int score; String itemName; public BarBean(int score, String itemName) { this.score = score; this.itemName = itemName; } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public String getItemName() { return itemName; } public void setItemName(String itemName) { this.itemName = itemName; } } //根据xml的设定获取宽度 private int measureWidth(int measureSpec) { int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); //wrap_content if (specMode == MeasureSpec.AT_MOST) { } //fill_parent或者精确值 else if (specMode == MeasureSpec.EXACTLY) { } Log.i("这个控件的宽度----------", "specMode=" + specMode + " specSize=" + specSize); return specSize; } //根据xml的设定获取高度 private int measureHeight(int measureSpec) { int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); //wrap_content if (specMode == MeasureSpec.AT_MOST) { } //fill_parent或者精确值 else if (specMode == MeasureSpec.EXACTLY) { } Log.i("这个控件的高度----------", "specMode:" + specMode + " specSize:" + specSize); return specSize; } }
三.自定义垂直柱状图
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.os.Build; import android.support.annotation.RequiresApi; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Display; import android.view.View; import android.view.WindowManager; import android.graphics.Paint.FontMetricsInt; import java.util.ArrayList; /** * Created by ${qc} on 2018/12/18. * 条形图 */ public class HistogramView extends View{ private Paint mPaint; private Rect mRect; private int mWidth; private int mHeight; private int mPaddingStart; private int mPaddingEnd; private int mPaddingTop; private int mPaddingBottom; private int mLeft; private int mTop; private int mRight; private int mBottom; private Context mContext; private ArrayListmBarLists; public HistogramView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; initData(); } public HistogramView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HistogramView(Context context) { this(context, null); } private void initData() { mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mRect = new Rect(); // default data mBarLists = new ArrayList (); Bar bar1 = new Bar(1, 0.3f, Color.CYAN, "one", "30"); Bar bar2 = new Bar(2, 0.55f, Color.GREEN, "two", "55"); Bar bar3 = new Bar(3, 0.8f, Color.BLUE, "three", "80"); mBarLists.add(bar1); mBarLists.add(bar2); mBarLists.add(bar3); } public void setBarLists(ArrayList barLists){ mBarLists = barLists; postInvalidate(); } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mWidth = getSizeFromMeasureSpec(widthMeasureSpec, 480); mHeight = getSizeFromMeasureSpec(heightMeasureSpec, 480); mPaddingStart = getPaddingStart(); mPaddingEnd = getPaddingEnd(); mPaddingTop = getPaddingTop(); mPaddingBottom = getPaddingBottom(); mLeft = mPaddingStart; mTop = mPaddingTop; mRight = mWidth - mPaddingEnd; mBottom = mHeight - mPaddingBottom; setMeasuredDimension(mWidth, mHeight); } @Override protected void onDraw(Canvas canvas) { // set background canvas.drawColor(Color.RED); mRect.set(mLeft, mTop, mRight, mBottom); mPaint.setColor(Color.WHITE); canvas.drawRect(mRect, mPaint); //*/ // 设置底部文字属性 mPaint.setTextSize(sp2Px(mContext, 11)); mPaint.setTextAlign(Paint.Align.CENTER); FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt(); int fontHeight = (int) Math.ceil(fontMetricsInt.bottom - fontMetricsInt.top); int N = mBarLists.size(); int UNIT_WIDTH = (mRight - mLeft) / (2 * N + 1); int left = 0; int top = 0; int right = 0; int bottom = 0; // 逐个画bar for (int i = 0; i < N; i++) { Bar bar = mBarLists.get(i); // 画 bar 底部文字 left = (int) (mLeft + (i * 2 + 0.5f) * UNIT_WIDTH); right = left + UNIT_WIDTH * 2; top = mBottom - fontHeight; bottom = mBottom; mRect.set(left, top, right, bottom); int baseLine = (mRect.top + mRect.bottom - fontMetricsInt.top - fontMetricsInt.bottom) / 2; mPaint.setColor(Color.BLACK); canvas.drawText(bar.bootomText, mRect.centerX(), baseLine, mPaint); // 画 bar 图形 left = mLeft + (i * 2 + 1) * UNIT_WIDTH; right = left + UNIT_WIDTH; bottom = mBottom - fontHeight; top = bottom - (int) ((mBottom - mTop - fontHeight * 2) * bar.ratio); mRect.set(left, top, right, bottom); mPaint.setColor(bar.color); canvas.drawRect(mRect, mPaint); // 画 bar 顶部文字 left = (int) (mLeft + (i * 2 + 0.5f) * UNIT_WIDTH); right = left + UNIT_WIDTH * 2; bottom = top; top = top - fontHeight; mRect.set(left, top, right, bottom); baseLine = (mRect.top + mRect.bottom - fontMetricsInt.top - fontMetricsInt.bottom) / 2; mPaint.setColor(Color.BLACK); canvas.drawText(bar.topText, mRect.centerX(), baseLine, mPaint); } // 画线 // mPaint.setColor(Color.BLACK); // canvas.drawLine(mLeft, mBottom - fontHeight, mRight, mBottom - fontHeight, mPaint); // canvas.drawLine(mLeft, mTop + fontHeight, mRight, mTop + fontHeight, mPaint); super.onDraw(canvas); } public class Bar { public int id; public float ratio; public int color; public String bootomText; public String topText; public Bar(int id, float ratio, int color, String bootomText, String topText) { this.id = id; this.ratio = ratio; this.color = color; this.bootomText = bootomText; this.topText = topText; } } // 工具类 public static int getSizeFromMeasureSpec(int measureSpec, int defaultSize) { int result = 0; int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); if(mode == MeasureSpec.EXACTLY){ result = size; } else { result = defaultSize; if(mode == MeasureSpec.AT_MOST){ result = Math.min(defaultSize, size); } } return result; } public static float sp2Px(Context context, float sp){ DisplayMetrics metrics = new DisplayMetrics(); WindowManager wm = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); display.getMetrics(metrics); float px = metrics.scaledDensity; return sp * px; } }
四.自定义扇形图
import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PathMeasure; import android.graphics.Point; import android.graphics.RectF; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; import android.view.WindowManager; import com.hjq.demo.R; import java.util.ArrayList; import java.util.List; import android.graphics.Path; /** * Created by ${qc} on 2018/12/18. */ public class RingView extends View { private Context mContext; private Paint mPaint; private int mPaintWidth = 0; // 画笔的宽 private int topMargin = 30; // 上边距 private int leftMargin = 80; // 左边距 private Resources mRes; private DisplayMetrics dm; private int showRateSize = 10; // 展示文字的大小 private int circleCenterX = 46; // 圆心点X 要与外圆半径相等 private int circleCenterY = 46; // 圆心点Y 要与外圆半径相等 private int ringOuterRidus = 46; // 外圆的半径 private int ringInnerRidus = 13; // 内圆的半径 private int ringPointRidus = 40; // 点所在圆的半径 private float rate = 0.4f; //点的外延距离 与 点所在圆半径的长度比率 private float extendLineWidth = 20; //点外延后 折的横线的长度 private RectF rectF; // 外圆所在的矩形 private RectF rectFPoint; // 点所在的矩形 private ListcolorList; private List rateList; private List titleList; private boolean isRing; private boolean isShowCenterPoint; private boolean isShowRate; public RingView(Context context) { super(context, null); } public RingView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); this.mContext = context; initView(); } public void setShow(List colorList, List rateList) { setShow(colorList, rateList, false); } public void setShow(List colorList, List rateList, boolean isRing) { setShow(colorList, rateList, isRing, false); } public void setShow(List colorList, List rateList, boolean isRing, boolean isShowRate) { setShow(colorList, rateList, isRing, isShowRate, false); } public void setData(List title){ this.titleList=title; } public void setShow(List colorList, List rateList, boolean isRing, boolean isShowRate, boolean isShowCenterPoint) { this.colorList = colorList; this.rateList = rateList; this.isRing = isRing; this.isShowRate = isShowRate; this.isShowCenterPoint = isShowCenterPoint; } private void initView() { this.mRes = mContext.getResources(); this.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); dm = new DisplayMetrics(); WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); wm.getDefaultDisplay().getMetrics(dm); int screenWidth = wm.getDefaultDisplay().getWidth(); // int height = wm.getDefaultDisplay().getHeight(); leftMargin = (px2dip(screenWidth) - (2 * circleCenterX)) / 2; mPaint.setColor(getResources().getColor(R.color.red)); mPaint.setStrokeWidth(dip2px(mPaintWidth)); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); rectF = new RectF(dip2px(mPaintWidth + leftMargin), dip2px(mPaintWidth + topMargin), dip2px(circleCenterX + ringOuterRidus + mPaintWidth * 2 + leftMargin), dip2px(circleCenterY + ringOuterRidus + mPaintWidth * 2 + topMargin)); rectFPoint = new RectF(dip2px(mPaintWidth + leftMargin + (ringOuterRidus - ringPointRidus)), dip2px(mPaintWidth + topMargin + (ringOuterRidus - ringPointRidus)), dip2px(circleCenterX + ringPointRidus + mPaintWidth * 2 + leftMargin), dip2px(circleCenterY + ringPointRidus + mPaintWidth * 2 + topMargin)); Log.e("矩形点:", dip2px(circleCenterX + ringOuterRidus + mPaintWidth * 2) + " --- " + dip2px(circleCenterY + ringOuterRidus + mPaintWidth * 2)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); pointList.clear(); if (colorList != null) { for (int i = 0; i < colorList.size(); i++) { mPaint.setColor(mRes.getColor(colorList.get(i))); mPaint.setStyle(Paint.Style.FILL); drawOuter(canvas, i); } } mPaint.setStyle(Paint.Style.FILL); if (isRing) { drawInner(canvas); } if (isShowCenterPoint) { drawCenterPoint(canvas); } } private void drawCenterPoint(Canvas canvas) { mPaint.setColor(mRes.getColor(R.color.red)); // Log.e("中心点:", dip2px(circleCenterX + mPaintWidth * 2 + leftMargin) + " --- " + dip2px(circleCenterY + mPaintWidth * 2 + topMargin)); canvas.drawCircle(dip2px(circleCenterX + mPaintWidth * 2 + leftMargin), dip2px(circleCenterY + mPaintWidth * 2 + topMargin), dip2px(1), mPaint); } private void drawInner(Canvas canvas) { mPaint.setColor(mRes.getColor(R.color.white)); // Log.e("内部圆点:", dip2px(circleCenterX + mPaintWidth * 2 + leftMargin) + " --- " + dip2px(circleCenterY + mPaintWidth * 2 + topMargin)); canvas.drawCircle(dip2px(circleCenterX + mPaintWidth * 2 + leftMargin), dip2px(circleCenterY + mPaintWidth * 2 + topMargin), dip2px(ringInnerRidus), mPaint); } private float preRate; private void drawArcCenterPoint(Canvas canvas, int position) { mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mRes.getColor(R.color.transparent)); mPaint.setStrokeWidth(dip2px(1)); canvas.drawArc(rectFPoint, preAngle, (endAngle) / 2, true, mPaint); dealPoint(rectFPoint, preAngle, (endAngle) / 2, pointArcCenterList); Point point = pointArcCenterList.get(position); mPaint.setColor(mRes.getColor(R.color.white)); canvas.drawCircle(point.x, point.y, dip2px(2), mPaint); if (preRate / 2 + rateList.get(position) / 2 < 5) { extendLineWidth += 20; rate -= 0.05f; } else { extendLineWidth = 20; rate = 0.4f; } // 外延画折线 float lineXPoint1 = (point.x - dip2px(leftMargin + ringOuterRidus)) * (1 + rate); float lineYPoint1 = (point.y - dip2px(topMargin + ringOuterRidus)) * (1 + rate); float[] floats = new float[8]; floats[0] = point.x; floats[1] = point.y; floats[2] = dip2px(leftMargin + ringOuterRidus) + lineXPoint1; floats[3] = dip2px(topMargin + ringOuterRidus) + lineYPoint1; floats[4] = dip2px(leftMargin + ringOuterRidus) + lineXPoint1; floats[5] = dip2px(topMargin + ringOuterRidus) + lineYPoint1; if (point.x >= dip2px(leftMargin + ringOuterRidus)) { mPaint.setTextAlign(Paint.Align.LEFT); floats[6] = dip2px(leftMargin + ringOuterRidus) + lineXPoint1 + dip2px(extendLineWidth); } else { mPaint.setTextAlign(Paint.Align.RIGHT); floats[6] = dip2px(leftMargin + ringOuterRidus) + lineXPoint1 - dip2px(extendLineWidth); } floats[7] = dip2px(topMargin + ringOuterRidus) + lineYPoint1; mPaint.setColor(mRes.getColor(colorList.get(position))); canvas.drawLines(floats, mPaint); mPaint.setTextSize(dip2px(showRateSize)); mPaint.setStyle(Paint.Style.STROKE); canvas.drawText(rateList.get(position) + "%", floats[6], floats[7] + dip2px(showRateSize) / 3, mPaint); // canvas.drawText(titleList.get(position),floats[6], floats[7] + dip2px(showRateSize) / 3 + dip2px(showRateSize) , mPaint); preRate = rateList.get(position); } List pointList = new ArrayList<>(); List pointArcCenterList = new ArrayList<>(); private void dealPoint(RectF rectF, float startAngle, float endAngle, List pointList) { Path orbit = new Path(); //通过Path类画一个90度(180—270)的内切圆弧路径 orbit.addArc(rectF, startAngle, endAngle); PathMeasure measure = new PathMeasure(orbit, false); Log.e("路径的测量长度:", "" + measure.getLength()); float[] coords = new float[]{0f, 0f}; //利用PathMeasure分别测量出各个点的坐标值coords int divisor = 1; measure.getPosTan(measure.getLength() / divisor, coords, null); Log.e("coords:", "x轴:" + coords[0] + " -- y轴:" + coords[1]); float x = coords[0]; float y = coords[1]; Point point = new Point(Math.round(x), Math.round(y)); pointList.add(point); } private void drawOuter(Canvas canvas, int position) { mPaint.setTextSize(dip2px(showRateSize)); canvas.drawCircle(circleCenterX, circleCenterY+position*circleCenterY, ringInnerRidus, mPaint); if (rateList != null) { endAngle = getAngle(rateList.get(position)); } // Log.e("preAngle:", "" + preAngle + " endAngle:" + endAngle); canvas.drawArc(rectF, preAngle, endAngle, true, mPaint); canvas.drawText(titleList.get(position),circleCenterX+dip2px(showRateSize), circleCenterY+position*circleCenterY+dip2px(showRateSize)/2,mPaint); dealPoint(rectF, preAngle, endAngle, pointList); if (isShowRate) { drawArcCenterPoint(canvas, position); } preAngle = preAngle + endAngle; } private float preAngle = -90; private float endAngle = -90; /** * @param percent 百分比 * @return */ private float getAngle(float percent) { float a = 360f / 100f * percent; return a; } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public int dip2px(float dpValue) { return (int) (dpValue * dm.density + 0.5f); } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public int px2dip(float pxValue) { return (int) (pxValue / dm.density + 0.5f); } }
xml中的使用
Activity中的使用
@BindView(R.id.radarview) CustomRadarView radarView;//雷达图 @BindView(R.id.score_checklist) HorizontalChartView scoreView;//水平柱状图 @BindView(R.id.histogramView) HistogramView histogramView;//垂直柱状图 @BindView(R.id.ringView) RingView ringView;//扇形图 @Override protected int getLayoutId() { return R.layout.activity_about; } @Override protected void initView() { Listdatas = new ArrayList<>(); datas.add(100.0);//语法100分 datas.add(80.0);//听力80分 datas.add(50.0);//口语90分 datas.add(70.0);//写作70分 datas.add(60.0);//阅读理解60分 List titles = new ArrayList<>(); titles.add("语法1"); titles.add("听力1"); titles.add("口语1"); titles.add("写作1"); titles.add("阅读理解1"); radarView.setValueTitle(titles); radarView.setData(datas); List barList = new ArrayList<>(); barList.add(new HorizontalChartView.BarBean(18, "听力")); barList.add(new HorizontalChartView.BarBean(5, "语法")); barList.add(new HorizontalChartView.BarBean(7, "词法")); barList.add(new HorizontalChartView.BarBean(20, "阅读理解")); barList.add(new HorizontalChartView.BarBean(10, "说")); scoreView.setBarList(barList); ArrayList barLists = new ArrayList (); for (int i = 0; i < 5; i++) { float ratio = (float) Math.random(); int color = (int) (Color.GRAY * ratio); HistogramView.Bar bar = histogramView.new Bar(i, ratio, color, "测试" + i, "10" + i); barLists.add(bar); } histogramView.setBarLists(barLists); // 添加的是颜色 List colorList = new ArrayList<>(); colorList.add(R.color.pink); colorList.add(R.color.orange); colorList.add(R.color.yellow); colorList.add(R.color.blue); // 添加的是百分比 List titleList=new ArrayList<>(); titleList.add("粉色"); titleList.add("橘色"); titleList.add("黄色"); titleList.add("蓝色"); List rateList = new ArrayList<>(); rateList.add(10f); rateList.add(5f); rateList.add(45f); rateList.add(40f); ringView.setData(titleList); ringView.setShow(colorList, rateList, false, true); }