在我们开发中我们经常会用到饼图,这个时候我们可以选中第三方库,进行修改定义我们需要的饼图,但是在实际开发中,我们三方库有时候并不能满足我们的需求,这个时候就需要我们进行自定绘制饼图,下面主要讲解的就是自定义饼图,主要解决了,由于饼图的分数太多而造成绘制的延长线以及说明挤到一块:
本篇主要将绘制大圆形分成左右两份,然后根据左右不同的数据进行绘制,从而避免了重叠的问题:
第一步:绘制饼图:
private void drawPie() { if (mCanvas == null) { return; } mCanvas.drawColor(backGroundColor); mPaint.setStyle(Paint.Style.FILL); float sum = 0; for (ItemType itemType : itemTypeList) { sum += itemType.widget; } float a = 360f / sum; float startRadius = defaultStartAngle; float sumRadius = 0; leftTypeList.clear(); rightTypeList.clear(); itemPoints.clear(); for (ItemType itemType : itemTypeList) { Log.e("timo-00", itemType.sleeptime); itemType.radius = itemType.widget * a; double al = 2 * Math.PI * ((startRadius + 90) / 360d); Point point = new Point((int) (width / 2 + radius * Math.sin(al)), (int) (height / 2 - radius * Math.cos(al))); if (cell > 0) { if (startRadius == defaultStartAngle) { firstPoint = point; } } double angle = 2 * Math.PI * ((startRadius + itemType.radius / 2) / 360d); double sin = -Math.sin(angle); double cos = -Math.cos(angle); if (cos > 0) { leftTypeList.add(itemType); } else { rightTypeList.add(itemType); } // Log.e("timo-00","sin:"+sin+" "+"cos:"+cos); sumRadius += Math.abs(itemType.radius); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(itemType.color); if (pieCell > 0) { if (sumRadius <= offRadius) { tempRectF.set(pieRectF.left - (float) (pieCell * cos), pieRectF.top - (float) (pieCell * sin), pieRectF.right - (float) (pieCell * cos), pieRectF.bottom - (float) (pieCell * sin)); mCanvas.drawArc(tempRectF, startRadius, itemType.radius, true, mPaint); } else { mCanvas.drawArc(tempRectF, startRadius, itemType.radius - (Math.abs(offRadius - sumRadius)), true, mPaint); break; } } else { /** * 1.PorterDuff.Mode.CLEAR * 所绘制不会提交到画布上。 * 2.PorterDuff.Mode.SRC * 显示上层绘制图片 * 3.PorterDuff.Mode.DST * 显示下层绘制图片 * 4.PorterDuff.Mode.SRC_OVER * 正常绘制显示,上下层绘制叠盖。 * 5.PorterDuff.Mode.DST_OVER * 上下层都显示。下层居上显示。 * 6.PorterDuff.Mode.SRC_IN * 取两层绘制交集。显示上层。 * 7.PorterDuff.Mode.DST_IN 不是 * 取两层绘制交集。显示下层。 * 8.PorterDuff.Mode.SRC_OUT * 取上层绘制非交集部分。 * 9.PorterDuff.Mode.DST_OUT * 取下层绘制非交集部分。 * 10.PorterDuff.Mode.SRC_ATOP * 取下层非交集部分与上层交集部分 * 11.PorterDuff.Mode.DST_ATOP * 取上层非交集部分与下层交集部分 * 12.PorterDuff.Mode.XOR * 异或:去除两图层交集部分 * 13.PorterDuff.Mode.DARKEN * 取两图层全部区域,交集部分颜色加深 * 14.PorterDuff.Mode.LIGHTEN * 取两图层全部,点亮交集部分颜色 * 15.PorterDuff.Mode.MULTIPLY * 取两图层交集部分叠加后颜色 * 16.PorterDuff.Mode.SCREEN * 取两图层全部区域,交集部分变为透明色 * */ if (sumRadius <= offRadius) { // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); mCanvas.drawArc(pieRectF, startRadius, itemType.radius, true, mPaint); } else { mCanvas.drawArc(pieRectF, startRadius, itemType.radius - (Math.abs(offRadius - sumRadius)), true, mPaint); break; } } startRadius += itemType.radius; if (cell > 0 && pieCell == 0) { mPaint.setColor(backGroundColor); mPaint.setStrokeWidth(cell); mCanvas.drawLine(getWidth() / 2, getHeight() / 2, point.x, point.y, mPaint); } } if (cell > 0 && firstPoint != null && pieCell == 0) { mPaint.setColor(backGroundColor); mPaint.setStrokeWidth(cell); // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); mCanvas.drawLine(getWidth() / 2, getHeight() / 2, firstPoint.x, firstPoint.y, mPaint); } mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(backGroundColor); if (innerRadius > 0 && pieCell == 0) { mCanvas.drawCircle(width / 2, height / 2, radius * innerRadius, mPaint); } }
第二步:绘制左边占比、延长线、说明文字以及饼图颜色
for (int i = 0; i < countright; i++) { mPath.reset(); ItemType itemType = leftTypeList.get(i); double angle = 2 * Math.PI * ((startRadius + itemType.radius / 2) / 360d); int x = (int) (width / 2 + radius * Math.cos(angle)); int y = (int) (height / 2 + radius * Math.sin(angle)); //百分比设置 Point startPoint = new Point(x, y); Point centerPoint = new Point((int) (width / 2 - radius * 1.2f), height / 2 - radius + h * (countright - 1 - i)); Point endPoint = new Point((int) (width * 0.2f), centerPoint.y); mPath.moveTo(startPoint.x, startPoint.y); mPath.lineTo(centerPoint.x, centerPoint.y); mPath.lineTo(endPoint.x, endPoint.y); resetPaint(); mPaint.setStrokeWidth(1); // mPaint.setColor(itemType.color); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(Color.parseColor("#FFFFFF")); mPaint.setStyle(Paint.Style.STROKE); mPathMeasure = new PathMeasure(mPath, false); drawLinePath.reset(); mPathMeasure.getSegment(0, mPathMeasure.getLength() * offLine, drawLinePath, true); mCanvas.drawPath(drawLinePath, mPaint); startRadius += itemType.radius; if (textAlpha > 0) { mPaint.setTextSize(itemTextSize); mPaint.setStyle(Paint.Style.FILL); mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setAlpha(textAlpha); if(title.contains("睡姿统计")){ //添加圆点 if (itemType.type.contains("坐")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_pick); Bitmap imageScale = imageScale(bitmap, 14, 14); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 -((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("仰")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_yellow); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 -((itemTextSize + textPadding) * 4 / 5)*3 , centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("左")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_green); Bitmap imageScale = imageScale(bitmap, 14, 14); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2-((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("俯")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_henblue); Bitmap imageScale = imageScale(bitmap, 14, 14); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 -((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("右")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_blue); Bitmap imageScale = imageScale(bitmap, 14, 14); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 -((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } mCanvas.drawText(itemType.type, centerPoint.x + (endPoint.x - centerPoint.x) / 2- (((itemTextSize + textPadding) * 4 / 5))*2+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); mPaint.setTextSize(itemTextSize * 4 / 5); //获取百分比 // mCanvas.drawText(itemType.getPercent(), x, y, mPaint); mCanvas.drawText(itemType.getNum(), centerPoint.x + (endPoint.x - centerPoint.x) / 2 -(((itemTextSize + textPadding) * 4 / 5))*2+itemTextSize+ textPadding+linePadding , centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); //获取时间 mCanvas.drawText(itemType.sleeptime, centerPoint.x + (endPoint.x - centerPoint.x) / 2- (((itemTextSize + textPadding) * 4 / 5))*2+itemTextSize+ textPadding , centerPoint.y - (itemTextSize + textPadding) * 4 / 5 + itemTextSize * 4 / 5, mPaint); } if (title.contains("睡眠分期")) { if (itemType.type.contains("觉醒")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_pick); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2-((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } else if (itemType.type.contains("浅睡眠")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_yellow); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 -((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } else if (itemType.type.contains("深睡眠")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_green); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 -((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } else if (itemType.type.contains("REM期")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_blue); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 -((itemTextSize + textPadding) * 4 / 5)*3, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } mCanvas.drawText(itemType.type, centerPoint.x + (endPoint.x - centerPoint.x) / 2- ((itemTextSize + textPadding) * 4 / 5), centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); mPaint.setTextSize(itemTextSize * 4 / 5); //获取百分比 // mCanvas.drawText(itemType.getPercent(), x, y, mPaint); mCanvas.drawText(itemType.getNum(), centerPoint.x + (endPoint.x - centerPoint.x) / 2+((itemTextSize + textPadding) * 4 / 5)+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); // mCanvas.drawText(itemType.getPercent(), x, y, mPaint); //获取具体数字 // mCanvas.drawText(itemType.getNum(), centerPoint.x + (endPoint.x - centerPoint.x) / 2, // centerPoint.y + (itemTextSize + textPadding) * 4 / 5, mPaint); //获取百分比数字 mCanvas.drawText(itemType.sleeptime, centerPoint.x + (endPoint.x - centerPoint.x) / 2- (itemTextSize + textPadding) * 4 / 5, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 + itemTextSize * 4 / 5, mPaint); } } }
第三步:绘制右边边占比、延长线、说明文字以及饼图颜色
//右边 for (int i = 0; i < countright; i++) { mPath.reset(); ItemType itemType = rightTypeList.get(i); double angle = 2 * Math.PI * ((startRadius + itemType.radius / 2) / 360d); int x = (int) (width / 2 + radius * Math.cos(angle)); int y = (int) (height / 2 + radius * Math.sin(angle)); Point startPoint = new Point(x, y); Point centerPoint = new Point((int) (width / 2 + radius * 1.2f), height / 2 - radius + h * (i)); Point endPoint = new Point((int) (width * 0.83f), centerPoint.y); mPath.moveTo(startPoint.x, startPoint.y); mPath.lineTo(centerPoint.x, centerPoint.y); mPath.lineTo(endPoint.x, endPoint.y); resetPaint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(Color.parseColor("#FFFFFF")); mPaint.setStyle(Paint.Style.STROKE); mPathMeasure = new PathMeasure(mPath, false); drawLinePath.reset(); mPathMeasure.getSegment(0, mPathMeasure.getLength() * offLine, drawLinePath, true); mCanvas.drawPath(drawLinePath, mPaint); startRadius += itemType.radius; if (textAlpha > 0) { mPaint.setTextSize(itemTextSize); mPaint.setStyle(Paint.Style.FILL); mPaint.setTextAlign(Paint.Align.CENTER); mPaint.setAlpha(textAlpha); if (title.contains("睡姿统计")) { //添加圆点 if (itemType.type.contains("坐")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_pick); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 + itemTextSize * 4 / 5, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("仰")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_yellow); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2+itemTextSize * 4 / 5, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("左")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_green); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 +itemTextSize * 4 / 5, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("俯")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_henblue); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 +itemTextSize * 4 / 5 , centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } else if (itemType.type.contains("右")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_blue); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 + itemTextSize * 4 / 5 , centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 - linePadding, null); } mCanvas.drawText(itemType.type, centerPoint.x + (endPoint.x - centerPoint.x) / 2+ (itemTextSize + textPadding) * 4 / 5+ itemTextSize +linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); mPaint.setTextSize(itemTextSize * 4 / 5); //获取百分比 // mCanvas.drawText(itemType.getPercent(), x, y, mPaint); mCanvas.drawText(itemType.getNum(), centerPoint.x + (endPoint.x - centerPoint.x) / 2 +((itemTextSize + textPadding) * 4 / 5)*2 + itemTextSize+textPadding+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); // mCanvas.drawText(itemType.getPercent(), x, y, mPaint); //获取具体数字 // mCanvas.drawText(itemType.getNum(), centerPoint.x + (endPoint.x - centerPoint.x) / 2, // centerPoint.y + (itemTextSize + textPadding) * 4 / 5, mPaint); //获取百分比数字 mCanvas.drawText(itemType.sleeptime, centerPoint.x + (endPoint.x - centerPoint.x) / 2+ (itemTextSize + textPadding) * 4 / 5+ itemTextSize*2+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 + itemTextSize * 4 / 5, mPaint); } if (title.contains("睡眠分期")) { if (itemType.type.contains("觉醒")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_pick); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2- itemTextSize * 4 / 5+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } else if (itemType.type.contains("浅睡眠")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_yellow); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 - itemTextSize * 4 / 5+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } else if (itemType.type.contains("深睡眠")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_green); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 - itemTextSize * 4 / 5+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } else if (itemType.type.contains("REM期")) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon_blue); Bitmap imageScale = imageScale(bitmap, 15, 15); mCanvas.drawBitmap(imageScale, centerPoint.x + (endPoint.x - centerPoint.x) / 2 - itemTextSize * 4 / 5+linePadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - itemTextSize * 4 / 5 , null); } mCanvas.drawText(itemType.type, centerPoint.x + (endPoint.x - centerPoint.x) / 2+ (itemTextSize + textPadding) * 4 / 5+textPadding, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); mPaint.setTextSize(itemTextSize * 4 / 5); //获取百分比 // mCanvas.drawText(itemType.getPercent(), x, y, mPaint); mCanvas.drawText(itemType.getNum(), centerPoint.x + (endPoint.x - centerPoint.x) / 2+((itemTextSize + textPadding) * 4 / 5)*2+itemTextSize*2 , centerPoint.y - (itemTextSize + textPadding) * 4 / 5 - linePadding, mPaint); // mCanvas.drawText(itemType.getPercent(), x, y, mPaint); //获取具体数字 // mCanvas.drawText(itemType.getNum(), centerPoint.x + (endPoint.x - centerPoint.x) / 2, // centerPoint.y + (itemTextSize + textPadding) * 4 / 5, mPaint); //获取百分比数字 mCanvas.drawText(itemType.sleeptime, centerPoint.x + (endPoint.x - centerPoint.x) / 2+ (itemTextSize + textPadding) * 4 / 5+ itemTextSize, centerPoint.y - (itemTextSize + textPadding) * 4 / 5 + itemTextSize * 4 / 5, mPaint); } } }
第四步:具体使用:
在xml文件中:
<com.view.PieChartView android:id="@+id/pieChartSleep" android:layout_width="match_parent" android:layout_height="175dp"/>
在调用的类中使用:
pieChartView.addItemType(new PieChartView.ItemType(split[0],Float.valueOf(split[1]),split[2], Color.parseColor("#F291C2")));
具体的代码,后续会上传成文件,以便大家下载修改使用。