package com.vanke.easysale.widget.chart; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.Rect; import android.graphics.RectF; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.view.View; import com.vanke.IntegratedPlatform.manager.R; import com.vanke.easysale.util.DensityUtil; import java.util.ArrayList; /** * 饼状图 * Created by rantao on 2017/8/26. */ public class PieChartView extends View { private int mWidth; // 控件宽度 private int mHeight; // 控件高度 private int mOuterRadius; // 外圆半径 private int mHoleRadius; // 内圆半径 private Paint mPaint; // 画笔 private int[] percentText = {}; // 百分比 private String[] mTexts = {}; // 线条上得文本 private int[] mColors = new int[]{getResources().getColor(R.color.color_e62e3d), getResources().getColor(R.color.color_ffd633), getResources().getColor(R.color.color_e5737c), getResources().getColor(R.color.color_991f29), getResources().getColor(R.color.color_ff0015) }; private int mCenterX; // 圆点X坐标 private int mCenterY; // 圆点Y坐标 private float mStartAngle = -90; // 圆弧开始角度 private ArrayList<PiePoint> mPiePoints = new ArrayList<>(); private int sumTextSize; private String sum = ""; public PieChartView(Context context) { super(context); } public PieChartView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mCenterX = mWidth / 2; mCenterY = mHeight / 2; drawArc(canvas); drawTextForHoleCenter(canvas); drawLine(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = measure(widthMeasureSpec); int height = measure(heightMeasureSpec); setMeasuredDimension(width, height); updateDimensions(width, height); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); updateDimensions(w, h); } private void updateDimensions(int width, int height) { this.mWidth = width; this.mHeight = height; } private int measure(int measureSpec) { int result = 0; int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); switch (mode) { case MeasureSpec.EXACTLY: result = size; break; case MeasureSpec.AT_MOST: result = size; break; case MeasureSpec.UNSPECIFIED: break; default: break; } return result; } public void setSum(String sum) { this.sum = sum; } public void setTexts(String[] mTexts) { this.mTexts = mTexts; } public void setPercentText(int[] percentText) { this.percentText = percentText; invalidate(); } /** * 初始化 */ private void init() { mOuterRadius = DensityUtil.dip2px(getContext(), 63); mHoleRadius = DensityUtil.dip2px(getContext(), 38); mPaint = new Paint(); mPaint.setAntiAlias(true); sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_18sp); } /** * 画圆弧 * * @param canvas */ private void drawArc(Canvas canvas) { if (null != mPiePoints && mPiePoints.size() > 0) { mPiePoints.clear(); } int startX = mCenterX - mOuterRadius; int endX = mCenterX + mOuterRadius; int startY = mCenterY - mOuterRadius; int endY = mCenterY + mOuterRadius; if (mStartAngle != -90) { mStartAngle = -90; } for (int i = 0; i < percentText.length; i++) { mPaint.setColor(mColors[i]); double ratio = ((double) percentText[i] / 100); float endAngle = (float) (ratio * 360); PiePoint piePoint = new PiePoint(); piePoint.startAngle = mStartAngle; piePoint.endAngle = mStartAngle + endAngle; mPiePoints.add(piePoint); canvas.drawArc(new RectF(startX, startY, endX, endY), mStartAngle, endAngle - 1, true, mPaint); mStartAngle = mStartAngle + endAngle; // 下一个开始角度 // 绘制阴影圆心部分 int left = mCenterX - mHoleRadius; int right = mCenterX + mHoleRadius; int top = mCenterY - mHoleRadius; int bottom = mCenterY + mHoleRadius; Bitmap centerBitmapWithShadow = BitmapFactory.decodeResource(getResources(), R.drawable.ic_piechart_shadow); canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG)); canvas.drawBitmap(centerBitmapWithShadow, null, new RectF(left, top, right, bottom), mPaint); } } /** * 绘制线条 * * @param canvas */ private void drawLine(Canvas canvas) { for (int i = 0; i < mPiePoints.size(); i++) { float centerAngle = (mPiePoints.get(i).startAngle + mPiePoints.get(i).endAngle) / 2; /** * 分四个象限和四个坐标轴进行判断 */ if (centerAngle > 0 && centerAngle < 90) { drawBreakLine(canvas, i, 1); } else if (centerAngle > 90 && centerAngle < 180) { drawBreakLine(canvas, i, 2); } else if (centerAngle > 180 && centerAngle < 270) { drawBreakLine(canvas, i, 3); } else if ((centerAngle > 270 && centerAngle < 360) || (centerAngle > -90 && centerAngle < 0)) { drawBreakLine(canvas, i, 4); } else if (centerAngle == 0) { drawBreakLine(canvas, i, 5); } else if (centerAngle == 90) { drawBreakLine(canvas, i, 6); } else if (centerAngle == 180) { drawBreakLine(canvas, i, 7); } else if (centerAngle == 270) { drawBreakLine(canvas, i, 8); } } } private void drawBreakLine(Canvas canvas, int position, int condition) { float centerAngle = (mPiePoints.get(position).startAngle + mPiePoints.get(position).endAngle) / 2; int xInArc = 0; // 圆弧中心在圆弧上的X坐标 int yInArc = 0; // 圆弧中心在圆弧上的Y坐标 int breakX = 0; // 拐点X坐标 int breakY = 0; // 拐点Y坐标 int lineEndX = 0; // 横线结束X坐标 int lineEndY = 0; // 横线结束Y坐标 float arcNum; mPaint.setColor(mColors[position]); switch (condition) { case 1: arcNum = (float) (Math.PI / 180 * centerAngle); xInArc = (int) (mCenterX + (Math.cos(arcNum) * mOuterRadius)); yInArc = (int) (mCenterY + (Math.sin(arcNum) * mOuterRadius)); breakX = xInArc + DensityUtil.dip2px(getContext(), 5); breakY = yInArc + DensityUtil.dip2px(getContext(), 5); lineEndX = breakX + DensityUtil.dip2px(getContext(), 70); lineEndY = breakY; canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint); canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX + DensityUtil.dip2px(getContext(), 10), lineEndY); break; case 2: arcNum = (float) (Math.PI / 180 * (centerAngle - 90)); xInArc = (int) (mCenterX - Math.sin(arcNum) * mOuterRadius); yInArc = (int) (mCenterY + Math.cos(arcNum) * mOuterRadius); breakX = xInArc - DensityUtil.dip2px(getContext(), 5); breakY = yInArc + DensityUtil.dip2px(getContext(), 5); lineEndX = breakX - DensityUtil.dip2px(getContext(), 70); lineEndY = breakY; canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint); canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX - DensityUtil.dip2px(getContext(), 10), lineEndY); break; case 3: arcNum = (float) (Math.PI / 180 * (centerAngle - 180)); xInArc = (int) (mCenterX - Math.cos(arcNum) * mOuterRadius); yInArc = (int) (mCenterY - Math.sin(arcNum) * mOuterRadius); breakX = xInArc - DensityUtil.dip2px(getContext(), 5); breakY = yInArc - DensityUtil.dip2px(getContext(), 5); lineEndX = breakX - DensityUtil.dip2px(getContext(), 70); lineEndY = breakY; canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint); canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX - DensityUtil.dip2px(getContext(), 10), lineEndY); break; case 4: arcNum = (float) (Math.PI / 180 * (centerAngle - 270)); xInArc = (int) (mCenterX + Math.sin(arcNum) * mOuterRadius); yInArc = (int) (mCenterY - Math.cos(arcNum) * mOuterRadius); breakX = xInArc + DensityUtil.dip2px(getContext(), 5); breakY = yInArc - DensityUtil.dip2px(getContext(), 5); lineEndX = breakX + DensityUtil.dip2px(getContext(), 70); lineEndY = breakY; canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint); canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX + DensityUtil.dip2px(getContext(), 10), lineEndY); break; case 5: // 0度 xInArc = mCenterX + mOuterRadius; yInArc = mCenterY; lineEndX = xInArc + DensityUtil.dip2px(getContext(), 70); lineEndY = yInArc; breakY = yInArc; canvas.drawLine(xInArc, yInArc, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX, lineEndY); break; case 6: // 90度 xInArc = mCenterX; yInArc = mCenterY + mOuterRadius; breakX = xInArc; breakY = yInArc + DensityUtil.dip2px(getContext(), 10); lineEndX = xInArc + DensityUtil.dip2px(getContext(), 70); lineEndY = breakY; canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint); canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX, lineEndY); break; case 7: // 180度 xInArc = mCenterX - mOuterRadius; yInArc = mCenterY; lineEndX = xInArc - DensityUtil.dip2px(getContext(), 70); lineEndY = yInArc; breakY = yInArc; canvas.drawLine(xInArc, yInArc, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX, lineEndY); break; case 8: // 270度 xInArc = mCenterX; yInArc = mCenterY - mOuterRadius; breakX = xInArc; breakY = yInArc - DensityUtil.dip2px(getContext(), 10); lineEndX = breakX + DensityUtil.dip2px(getContext(), 70); lineEndY = breakY; canvas.drawLine(xInArc, yInArc, breakX, breakY, mPaint); canvas.drawLine(breakX, breakY, lineEndX, lineEndY, mPaint); canvas.drawCircle(lineEndX, lineEndY, 5, mPaint); drawTextOnLine(canvas, position, xInArc, breakY, lineEndX); drawTextForEdge(canvas, position, condition, lineEndX, lineEndY); break; default: break; } } private void drawTextForHoleCenter(Canvas canvas) { if (percentText.length != 0) { /** * 绘制总数动态文本 */ int left = mCenterX - DensityUtil.dip2px(getContext(), 10); int right = mCenterX + DensityUtil.dip2px(getContext(), 10); int top = mCenterY + DensityUtil.dip2px(getContext(), 5); int bottom = mCenterY + DensityUtil.dip2px(getContext(), 15); Rect rect = new Rect(left, top, right, bottom); Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2; mPaint.setTextAlign(Paint.Align.CENTER); sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_18sp); mPaint.setTextSize(sumTextSize); mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_333333)); canvas.drawText(sum, rect.centerX(), baseline, mPaint); /** * 绘制"总数"静态文本 */ left = mCenterX - DensityUtil.dip2px(getContext(), 7); right = mCenterX + DensityUtil.dip2px(getContext(), 7); top = mCenterY - DensityUtil.dip2px(getContext(), 13); bottom = mCenterY - DensityUtil.dip2px(getContext(), 3); rect = new Rect(left, top, right, bottom); baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2; mPaint.setTextAlign(Paint.Align.CENTER); sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_12sp); mPaint.setTextSize(sumTextSize); mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999)); canvas.drawText("总数", rect.centerX(), baseline, mPaint); } } /** * 绘制线条上的文本 * * @param canvas */ private void drawTextOnLine(Canvas canvas, int position, int startX, int startY, int endX) { int startYTmp = startY - DensityUtil.dip2px(getContext(), 10); int endYTmp = startY - DensityUtil.dip2px(getContext(), 5); Rect rect = new Rect(startX, startYTmp, endX, endYTmp); Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2; mPaint.setTextAlign(Paint.Align.CENTER); sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_10sp); mPaint.setTextSize(sumTextSize); mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_999999)); canvas.drawText(mTexts[position], rect.centerX(), baseline, mPaint); } /** * 绘制线条边缘文本 * * @param canvas */ private void drawTextForEdge(Canvas canvas, int position, int codition, int edgeX, int centerY) { Rect rect = null; switch (codition) { case 1: rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX + DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5)); break; case 2: rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX - DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5)); break; case 3: rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX - DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5)); break; case 4: rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX + DensityUtil.dip2px(getContext(), 10), centerY + DensityUtil.dip2px(getContext(), 5)); break; case 5: // 0度 rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX + DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5)); break; case 6: // 90度 rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX + DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5)); break; case 7: // 180度 rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX - DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5)); break; case 8: // 270度 rect = new Rect(edgeX, centerY - DensityUtil.dip2px(getContext(), 5), edgeX + DensityUtil.dip2px(getContext(), 30), centerY + DensityUtil.dip2px(getContext(), 5)); break; default: break; } Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt(); int baseline = (rect.bottom + rect.top - fontMetrics.bottom - fontMetrics.top) / 2; mPaint.setTextAlign(Paint.Align.CENTER); sumTextSize = getResources().getDimensionPixelSize(R.dimen.textsize_12sp); mPaint.setTextSize(sumTextSize); mPaint.setColor(ContextCompat.getColor(getContext(), R.color.color_333333)); String percent = percentText[position] + "%"; canvas.drawText(percent, rect.centerX(), baseline, mPaint); } class PiePoint { float startAngle; float endAngle; } }
android实现饼状图
最新推荐文章于 2024-04-22 02:07:19 发布