当前位置:   article > 正文

android 图表开源库MPAndroidChart 实现PieChart 圆环颜色渐变效果_android com.github.mikephil.charting.charts.piecha

android com.github.mikephil.charting.charts.piechart 渐变

项目中图表控件用的是MPAndroidChart 开源库,在显示PieChart时想要实现圆环渐变色,在网上查找一番没有找到能实现这个效果的方式,经过一番搜索查找发现只要给PieChartRenderer 这个类的mRenderPaint 设置渐变的shader 即可,所以写一个类继承PieChartRenderer直接直接重写他的drawDataSet这个方法,其实也就是把他原来代码全部拷贝过来,然后做下调整,增加线性渐变,在设置渐变方向的时候需要获取到每个扇形的起始和结束点坐标,然后设置到LinearGradient 里面,这样才能保证渐变效果,同时对于只有一条数据的情况需要单独调整下渐变的起始和结束点,不然就没法产生渐变效果,最终实现的效果如下

  1. import android.graphics.Canvas;
  2. import android.graphics.LinearGradient;
  3. import android.graphics.Path;
  4. import android.graphics.RectF;
  5. import android.graphics.Shader;
  6. import com.github.mikephil.charting.animation.ChartAnimator;
  7. import com.github.mikephil.charting.charts.PieChart;
  8. import com.github.mikephil.charting.data.Entry;
  9. import com.github.mikephil.charting.interfaces.datasets.IPieDataSet;
  10. import com.github.mikephil.charting.renderer.PieChartRenderer;
  11. import com.github.mikephil.charting.utils.MPPointF;
  12. import com.github.mikephil.charting.utils.Utils;
  13. import com.github.mikephil.charting.utils.ViewPortHandler;
  14. import com.socks.library.KLog;
  15. public class SuddleBluePieChartRenderer extends PieChartRenderer {
  16. private Path mPathBuffer = new Path();
  17. private RectF mInnerRectBuffer = new RectF();
  18. public SuddleBluePieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
  19. super(chart, animator, viewPortHandler);
  20. }
  21. @Override
  22. protected void drawDataSet(Canvas c, IPieDataSet dataSet) {
  23. float angle = 0;
  24. float rotationAngle = mChart.getRotationAngle();
  25. float phaseX = mAnimator.getPhaseX();
  26. float phaseY = mAnimator.getPhaseY();
  27. final RectF circleBox = mChart.getCircleBox();
  28. final int entryCount = dataSet.getEntryCount();
  29. final float[] drawAngles = mChart.getDrawAngles();
  30. final MPPointF center = mChart.getCenterCircleBox();
  31. final float radius = mChart.getRadius();
  32. final boolean drawInnerArc = mChart.isDrawHoleEnabled() && !mChart.isDrawSlicesUnderHoleEnabled();
  33. final float userInnerRadius = drawInnerArc
  34. ? radius * (mChart.getHoleRadius() / 100.f)
  35. : 0.f;
  36. final float roundedRadius = (radius - (radius * mChart.getHoleRadius() / 100f)) / 2f;
  37. final RectF roundedCircleBox = new RectF();
  38. final boolean drawRoundedSlices = drawInnerArc && mChart.isDrawRoundedSlicesEnabled();
  39. int visibleAngleCount = 0;
  40. for (int j = 0; j < entryCount; j++) {
  41. // draw only if the value is greater than zero
  42. if ((Math.abs(dataSet.getEntryForIndex(j).getY()) > Utils.FLOAT_EPSILON)) {
  43. visibleAngleCount++;
  44. }
  45. }
  46. final float sliceSpace = visibleAngleCount <= 1 ? 0.f : getSliceSpace(dataSet);
  47. for (int j = 0; j < entryCount; j++) {
  48. // mRenderPaint.setShader(new LinearGradient(mChart.getWidth()/2 , mChart.getWidth()/2 -radius, mChart.getWidth()/2, mChart.getWidth()/2+radius,
  49. // mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
  50. // mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
  51. // int[] colors = new int[]{mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
  52. // mChart.getData().getDataSet().getGradientColor(j).getEndColor()};
  53. // mRenderPaint.setShader(new SweepGradient(radius,radius,colors,null));
  54. float sliceAngle = drawAngles[j];
  55. float innerRadius = userInnerRadius;
  56. Entry e = dataSet.getEntryForIndex(j);
  57. // draw only if the value is greater than zero
  58. if (!(Math.abs(e.getY()) > Utils.FLOAT_EPSILON)) {
  59. angle += sliceAngle * phaseX;
  60. continue;
  61. }
  62. // Don't draw if it's highlighted, unless the chart uses rounded slices
  63. if (mChart.needsHighlight(j) && !drawRoundedSlices) {
  64. angle += sliceAngle * phaseX;
  65. continue;
  66. }
  67. final boolean accountForSliceSpacing = sliceSpace > 0.f && sliceAngle <= 180.f;
  68. mRenderPaint.setColor(dataSet.getColor(j));
  69. final float sliceSpaceAngleOuter = visibleAngleCount == 1 ?
  70. 0.f :
  71. sliceSpace / (Utils.FDEG2RAD * radius);
  72. final float startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.f) * phaseY;
  73. float sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * phaseY;
  74. if (sweepAngleOuter < 0.f) {
  75. sweepAngleOuter = 0.f;
  76. }
  77. mPathBuffer.reset();
  78. if (drawRoundedSlices) {
  79. float x = center.x + (radius - roundedRadius) * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
  80. float y = center.y + (radius - roundedRadius) * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
  81. roundedCircleBox.set(x - roundedRadius, y - roundedRadius, x + roundedRadius, y + roundedRadius);
  82. }
  83. float arcStartPointX = center.x + radius * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
  84. float arcStartPointY = center.y + radius * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
  85. if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
  86. // Android is doing "mod 360"
  87. mPathBuffer.addCircle(center.x, center.y, radius, Path.Direction.CW);
  88. } else {
  89. if (drawRoundedSlices) {
  90. mPathBuffer.arcTo(roundedCircleBox, startAngleOuter + 180, -180);
  91. }
  92. mPathBuffer.arcTo(
  93. circleBox,
  94. startAngleOuter,
  95. sweepAngleOuter
  96. );
  97. }
  98. // API < 21 does not receive floats in addArc, but a RectF
  99. mInnerRectBuffer.set(
  100. center.x - innerRadius,
  101. center.y - innerRadius,
  102. center.x + innerRadius,
  103. center.y + innerRadius);
  104. // mRenderPaint.setShader(new LinearGradient(center.x - innerRadius,
  105. // center.y - innerRadius,
  106. // center.x + innerRadius,
  107. // center.y + innerRadius,
  108. // mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
  109. // mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
  110. // KLog.i(" xp "+mChart.getData().getDataSet().getXValuePosition()+" yp "+mChart.getData().getDataSet().getYValuePosition());
  111. // 获取每个扇形的起始点和结束点坐标
  112. // float startAngleOuter1 = rotationAngle + (angle + sliceSpaceAngleOuter / 2.f) * phaseY;
  113. float endAngleOuter = startAngleOuter + sweepAngleOuter;
  114. float startX = center.x + radius * (float) Math.cos(startAngleOuter * Utils.FDEG2RAD);
  115. float startY = center.y + radius * (float) Math.sin(startAngleOuter * Utils.FDEG2RAD);
  116. float endX = center.x + radius * (float) Math.cos(endAngleOuter * Utils.FDEG2RAD);
  117. float endY = center.y + radius * (float) Math.sin(endAngleOuter * Utils.FDEG2RAD);
  118. KLog.i("startX "+startX+" startY "+startY +" endX "+endX+" endY "+endY);
  119. if (entryCount == 1)
  120. {
  121. mRenderPaint.setShader(new LinearGradient(center.x - innerRadius,
  122. center.y - innerRadius,
  123. center.x + innerRadius,
  124. center.y + innerRadius,
  125. mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
  126. mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
  127. }
  128. else
  129. {
  130. mRenderPaint.setShader(new LinearGradient(startX,
  131. startY,
  132. endX ,
  133. endY,
  134. mChart.getData().getDataSet().getGradientColor(j).getStartColor(),
  135. mChart.getData().getDataSet().getGradientColor(j).getEndColor(), Shader.TileMode.CLAMP));
  136. }
  137. if (drawInnerArc && (innerRadius > 0.f || accountForSliceSpacing)) {
  138. if (accountForSliceSpacing) {
  139. float minSpacedRadius =
  140. calculateMinimumRadiusForSpacedSlice(
  141. center, radius,
  142. sliceAngle * phaseY,
  143. arcStartPointX, arcStartPointY,
  144. startAngleOuter,
  145. sweepAngleOuter);
  146. if (minSpacedRadius < 0.f)
  147. minSpacedRadius = -minSpacedRadius;
  148. innerRadius = Math.max(innerRadius, minSpacedRadius);
  149. }
  150. final float sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.f ?
  151. 0.f :
  152. sliceSpace / (Utils.FDEG2RAD * innerRadius);
  153. final float startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.f) * phaseY;
  154. float sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * phaseY;
  155. if (sweepAngleInner < 0.f) {
  156. sweepAngleInner = 0.f;
  157. }
  158. final float endAngleInner = startAngleInner + sweepAngleInner;
  159. if (sweepAngleOuter >= 360.f && sweepAngleOuter % 360f <= Utils.FLOAT_EPSILON) {
  160. // Android is doing "mod 360"
  161. mPathBuffer.addCircle(center.x, center.y, innerRadius, Path.Direction.CCW);
  162. } else {
  163. if (drawRoundedSlices) {
  164. float x = center.x + (radius - roundedRadius) * (float) Math.cos(endAngleInner * Utils.FDEG2RAD);
  165. float y = center.y + (radius - roundedRadius) * (float) Math.sin(endAngleInner * Utils.FDEG2RAD);
  166. roundedCircleBox.set(x - roundedRadius, y - roundedRadius, x + roundedRadius, y + roundedRadius);
  167. mPathBuffer.arcTo(roundedCircleBox, endAngleInner, 180);
  168. } else
  169. mPathBuffer.lineTo(
  170. center.x + innerRadius * (float) Math.cos(endAngleInner * Utils.FDEG2RAD),
  171. center.y + innerRadius * (float) Math.sin(endAngleInner * Utils.FDEG2RAD));
  172. mPathBuffer.arcTo(
  173. mInnerRectBuffer,
  174. endAngleInner,
  175. -sweepAngleInner
  176. );
  177. }
  178. } else {
  179. if (sweepAngleOuter % 360f > Utils.FLOAT_EPSILON) {
  180. if (accountForSliceSpacing) {
  181. float angleMiddle = startAngleOuter + sweepAngleOuter / 2.f;
  182. float sliceSpaceOffset =
  183. calculateMinimumRadiusForSpacedSlice(
  184. center,
  185. radius,
  186. sliceAngle * phaseY,
  187. arcStartPointX,
  188. arcStartPointY,
  189. startAngleOuter,
  190. sweepAngleOuter);
  191. float arcEndPointX = center.x +
  192. sliceSpaceOffset * (float) Math.cos(angleMiddle * Utils.FDEG2RAD);
  193. float arcEndPointY = center.y +
  194. sliceSpaceOffset * (float) Math.sin(angleMiddle * Utils.FDEG2RAD);
  195. mPathBuffer.lineTo(
  196. arcEndPointX,
  197. arcEndPointY);
  198. } else {
  199. mPathBuffer.lineTo(
  200. center.x,
  201. center.y);
  202. }
  203. }
  204. }
  205. mPathBuffer.close();
  206. mBitmapCanvas.drawPath(mPathBuffer, mRenderPaint);
  207. angle += sliceAngle * phaseX;
  208. }
  209. mRenderPaint.setShader(null);
  210. MPPointF.recycleInstance(center);
  211. }
  212. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/254795?site
推荐阅读
相关标签
  

闽ICP备14008679号