赞
踩
项目中图表控件用的是MPAndroidChart 开源库,在显示PieChart时想要实现圆环渐变色,在网上查找一番没有找到能实现这个效果的方式,经过一番搜索查找发现只要给PieChartRenderer 这个类的mRenderPaint 设置渐变的shader 即可,所以写一个类继承PieChartRenderer直接直接重写他的drawDataSet这个方法,其实也就是把他原来代码全部拷贝过来,然后做下调整,增加线性渐变,在设置渐变方向的时候需要获取到每个扇形的起始和结束点坐标,然后设置到LinearGradient 里面,这样才能保证渐变效果,同时对于只有一条数据的情况需要单独调整下渐变的起始和结束点,不然就没法产生渐变效果,最终实现的效果如下
-
-
- import android.graphics.Canvas;
- import android.graphics.LinearGradient;
- import android.graphics.Path;
- import android.graphics.RectF;
- import android.graphics.Shader;
-
- import com.github.mikephil.charting.animation.ChartAnimator;
- import com.github.mikephil.charting.charts.PieChart;
- import com.github.mikephil.charting.data.Entry;
- import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
- import com.github.mikephil.charting.renderer.PieChartRenderer;
- import com.github.mikephil.charting.utils.MPPointF;
- import com.github.mikephil.charting.utils.Utils;
- import com.github.mikephil.charting.utils.ViewPortHandler;
- import com.socks.library.KLog;
-
-
- public class SuddleBluePieChartRenderer extends PieChartRenderer {
- private Path mPathBuffer = new Path();
- private RectF mInnerRectBuffer = new RectF();
- public SuddleBluePieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
- super(chart, animator, viewPortHandler);
- }
-
-
- @Override
- protected void drawDataSet(Canvas c, IPieDataSet dataSet) {
-
- float angle = 0;
- float rotationAngle = mChart.getRotationAngle();
-
- float phaseX = mAnimator.getPhaseX();
- float phaseY = mAnimator.getPhaseY();
-
- final RectF circleBox = mChart.getCircleBox();
-
- final int entryCount = dataSet.getEntryCount();
- final float[] drawAngles = mChart.getDrawAngles();
- final MPPointF center = mChart.getCenterCircleBox();
- final float radius = mChart.getRadius();
- final boolean drawInnerArc = mChart.isDrawHoleEnabled() && !mChart.isDrawSlicesUnderHoleEnabled();
- final float userInnerRadius = drawInnerArc
- ? radius * (mChart.getHoleRadius() / 100.f)
- : 0.f;
- final float roundedRadius = (radius - (radius * mChart.getHoleRadius() / 100f)) / 2f;
- final RectF roundedCircleBox = new RectF();
- final boolean drawRoundedSlices = drawInnerArc && mChart.isDrawRoundedSlicesEnabled();
-
- int visibleAngleCount = 0;
- for (int j = 0; j < entryCount; j++) {
- // draw only if the value is greater than zero
- if ((Math.abs(dataSet.getEntryForIndex(j).getY()) > Utils.FLOAT_EPSILON)) {
- visibleAngleCount++;
- }
- }
-
- final float sliceSpace = visibleAngleCount <= 1 ? 0.f : getSliceSpace(dataSet);
-
- for (int j = 0; j < entryCount; j++) {
-
-
- // mRenderPaint.setShader(new LinearGradient(mChart.getWidth()/2 , mChart.getWidth()/2 -radius, mChart.getWidth()/2, mChart.getWidth()/2+radius,
- // mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
- // mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
-
- // int[] colors = new int[]{mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
- // mChart.getData().getDataSet().getGradientColor(j).getEndColor()};
- // mRenderPaint.setShader(new SweepGradient(radius,radius,colors,null));
-
- float sliceAngle = drawAngles[j];
- float innerRadius = userInnerRadius;
-
- Entry e = dataSet.getEntryForIndex(j);
-
- // draw only if the value is greater than zero
- if (!(Math.abs(e.getY()) > Utils.FLOAT_EPSILON)) {
- angle += sliceAngle * phaseX;
- continue;
- }
-
- // Don't draw if it's highlighted, unless the chart uses rounded slices
- if (mChart.needsHighlight(j) && !drawRoundedSlices) {
- angle += sliceAngle * phaseX;
- continue;
- }
-
- final boolean accountForSliceSpacing = sliceSpace > 0.f && sliceAngle <= 180.f;
-
- mRenderPaint.setColor(dataSet.getColor(j));
-
- final float sliceSpaceAngleOuter = visibleAngleCount == 1 ?
- 0.f :
- sliceSpace / (Utils.FDEG2RAD * radius);
- final float startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.f) * phaseY;
- float sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * phaseY;
- if (sweepAngleOuter < 0.f) {
- sweepAngleOuter = 0.f;
- }
-
- mPathBuffer.reset();
-
- if (drawRoundedSlices) {
- float x = center.x + (radius - roundedRadius) * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
- float y = center.y + (radius - roundedRadius) * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
- roundedCircleBox.set(x - roundedRadius, y - roundedRadius, x + roundedRadius, y + roundedRadius);
- }
-
- float arcStartPointX = center.x + radius * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
- float arcStartPointY = center.y + radius * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
-
- if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
- // Android is doing "mod 360"
- mPathBuffer.addCircle(center.x, center.y, radius, Path.Direction.CW);
- } else {
-
- if (drawRoundedSlices) {
- mPathBuffer.arcTo(roundedCircleBox, startAngleOuter + 180, -180);
- }
-
- mPathBuffer.arcTo(
- circleBox,
- startAngleOuter,
- sweepAngleOuter
- );
- }
-
- // API < 21 does not receive floats in addArc, but a RectF
- mInnerRectBuffer.set(
- center.x - innerRadius,
- center.y - innerRadius,
- center.x + innerRadius,
- center.y + innerRadius);
-
- // mRenderPaint.setShader(new LinearGradient(center.x - innerRadius,
- // center.y - innerRadius,
- // center.x + innerRadius,
- // center.y + innerRadius,
- // mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
- // mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
-
- // KLog.i(" xp "+mChart.getData().getDataSet().getXValuePosition()+" yp "+mChart.getData().getDataSet().getYValuePosition());
-
- // 获取每个扇形的起始点和结束点坐标
- // float startAngleOuter1 = rotationAngle + (angle + sliceSpaceAngleOuter / 2.f) * phaseY;
- float endAngleOuter = startAngleOuter + sweepAngleOuter;
-
- float startX = center.x + radius * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
- float startY = center.y + radius * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
-
- float endX = center.x + radius * (float) Math.cos(endAngleOuter * Utils.FDEG2RAD);
- float endY = center.y + radius * (float) Math.sin(endAngleOuter * Utils.FDEG2RAD);
-
- KLog.i("startX "+startX+" startY "+startY +" endX "+endX+" endY "+endY);
- if (entryCount == 1)
- {
- mRenderPaint.setShader(new LinearGradient(center.x - innerRadius,
- center.y - innerRadius,
- center.x + innerRadius,
- center.y + innerRadius,
- mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
- mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
- }
- else
- {
- mRenderPaint.setShader(new LinearGradient(startX,
- startY,
- endX ,
- endY,
- mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
- mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
- }
-
-
-
-
-
- if (drawInnerArc && (innerRadius > 0.f || accountForSliceSpacing)) {
-
- if (accountForSliceSpacing) {
- float minSpacedRadius =
- calculateMinimumRadiusForSpacedSlice(
- center, radius,
- sliceAngle * phaseY,
- arcStartPointX, arcStartPointY,
- startAngleOuter,
- sweepAngleOuter);
-
- if (minSpacedRadius < 0.f)
- minSpacedRadius = -minSpacedRadius;
-
- innerRadius = Math.max(innerRadius, minSpacedRadius);
- }
-
- final float sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.f ?
- 0.f :
- sliceSpace / (Utils.FDEG2RAD * innerRadius);
- final float startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.f) * phaseY;
- float sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * phaseY;
- if (sweepAngleInner < 0.f) {
- sweepAngleInner = 0.f;
- }
- final float endAngleInner = startAngleInner + sweepAngleInner;
-
- if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
- // Android is doing "mod 360"
- mPathBuffer.addCircle(center.x, center.y, innerRadius, Path.Direction.CCW);
- } else {
-
- if (drawRoundedSlices) {
- float x = center.x + (radius - roundedRadius) * (float) Math.cos(endAngleInner * Utils.FDEG2RAD);
- float y = center.y + (radius - roundedRadius) * (float) Math.sin(endAngleInner * Utils.FDEG2RAD);
- roundedCircleBox.set(x - roundedRadius, y - roundedRadius, x + roundedRadius, y + roundedRadius);
- mPathBuffer.arcTo(roundedCircleBox, endAngleInner, 180);
- } else
- mPathBuffer.lineTo(
- center.x + innerRadius * (float) Math.cos(endAngleInner * Utils.FDEG2RAD),
- center.y + innerRadius * (float) Math.sin(endAngleInner * Utils.FDEG2RAD));
-
- mPathBuffer.arcTo(
- mInnerRectBuffer,
- endAngleInner,
- -sweepAngleInner
- );
- }
- } else {
-
- if (sweepAngleOuter % 360f > Utils.FLOAT_EPSILON) {
- if (accountForSliceSpacing) {
-
- float angleMiddle = startAngleOuter + sweepAngleOuter / 2.f;
-
- float sliceSpaceOffset =
- calculateMinimumRadiusForSpacedSlice(
- center,
- radius,
- sliceAngle * phaseY,
- arcStartPointX,
- arcStartPointY,
- startAngleOuter,
- sweepAngleOuter);
-
- float arcEndPointX = center.x +
- sliceSpaceOffset * (float) Math.cos(angleMiddle * Utils.FDEG2RAD);
- float arcEndPointY = center.y +
- sliceSpaceOffset * (float) Math.sin(angleMiddle * Utils.FDEG2RAD);
-
- mPathBuffer.lineTo(
- arcEndPointX,
- arcEndPointY);
-
-
- } else {
- mPathBuffer.lineTo(
- center.x,
- center.y);
- }
- }
-
- }
-
- mPathBuffer.close();
-
- mBitmapCanvas.drawPath(mPathBuffer, mRenderPaint);
-
- angle += sliceAngle * phaseX;
- }
- mRenderPaint.setShader(null);
-
- MPPointF.recycleInstance(center);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。