Android绘制简单饼状图


原项目地址:https://github.com/limccn/Android-Charts

因为在项目中需要用到绘制饼状图,所以对github下的android-charts库进行了精简和修改,貌似该库本身有些bug,例如文字绘制有时候会错位,我改了一些地方,有兴趣的可以将下面所有代码复制进自己项目中,使用方法如下:

 mData[0] = new ArrayList<TitleValueColorEntity>();
 for(int i=0; i<5; i++) {
  mData[0].add(new TitleValueColorEntity(mTitle[i],
    needTime[i],
    this.getResources().getColor(mColorsId[i])));
 }

 mPieChart.setData(mData[2]);

源码:

/*
 * BaseChart.java
 * Android-Charts
 *
 * Created by limc on 2013.
 *
 * Copyright 2011 limc.cn All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.nekocode.xuedao.piechart;

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

public class BaseChart extends View {

 /*
  * (non-Javadoc)
  *
  * @param context
  *
  * @see android.view.View#BaseChart(Context)
  */
 public BaseChart(Context context) {
  super(context);
 }

 /*
  * (non-Javadoc)
  *
  * @param context
  *
  * @param attrs
  *
  * @see android.view.View#BaseChart(Context, AttributeSet)
  */
 public BaseChart(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

 /*
  * (non-Javadoc)
  *
  * @param context
  *
  * @param attrs
  *
  * @param defStyle
  *
  * @see android.view.View#BaseChart(Context, AttributeSet, int)
  */
 public BaseChart(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
 }

 /*
  * (non-Javadoc)
  *
  * @param widthMeasureSpec
  *
  * @param heightMeasureSpec
  *
  * @see android.view.View#onMeasure(int, int)
  */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  setMeasuredDimension(measureWidth(widthMeasureSpec),
    measureHeight(heightMeasureSpec));
 }

 /*
  * (non-Javadoc)
  *
  * @param gainFocus
  *
  * @param direction
  *
  * @param previouslyFocusedRect
  *
  * @see android.view.View#onFocusChanged(boolean, int,
  * android.graphics.Rect)
  */
 @Override
 protected void onFocusChanged(boolean gainFocus, int direction,
   Rect previouslyFocusedRect) {
  super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
 }

 private int measureWidth(int measureSpec) {
  int result = 0;
  int specMode = MeasureSpec.getMode(measureSpec);
  int specSize = MeasureSpec.getSize(measureSpec);

  if (specMode == MeasureSpec.EXACTLY) {
   result = specSize;
  } else if (specMode == MeasureSpec.AT_MOST) {
   result = Math.min(result, specSize);
  }
  return result;
 }

 private int measureHeight(int measureSpec) {
  int result = 0;
  int specMode = MeasureSpec.getMode(measureSpec);
  int specSize = MeasureSpec.getSize(measureSpec);

  if (specMode == MeasureSpec.EXACTLY) {
   result = specSize;
  } else if (specMode == MeasureSpec.AT_MOST) {
   result = Math.min(result, specSize);
  }
  return result;
 }
}

---------------------------------分割线---------------------------------

/*
 * PieChart.java
 * Android-Charts
 *
 * Created by limc on 2011/05/29.
 *
 * Copyright 2011 limc.cn All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 *
 */
package com.nekocode.xuedao.piechart;

import java.util.List;

import com.nekocode.xuedao.utils.MyUtils;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.util.AttributeSet;

public class PieChart extends BaseChart {
 public static final String DEFAULT_TITLE = "Pie Chart";
 public static final boolean DEFAULT_DISPLAY_RADIUS = true;
 public static final int DEFAULT_RADIUS_LENGTH = 80;
 public static final int DEFAULT_RADIUS_COLOR = Color.WHITE;
 public static final int DEFAULT_CIRCLE_BORDER_COLOR = Color.WHITE;
 public static final Point DEFAULT_POSITION = new Point(0, 0);


 private List<TitleValueColorEntity> data;
 private String title = DEFAULT_TITLE;
 private Point position = DEFAULT_POSITION;
 private int radiusLength = DEFAULT_RADIUS_LENGTH;
 private int radiusColor = DEFAULT_RADIUS_COLOR;
 private int circleBorderColor = DEFAULT_CIRCLE_BORDER_COLOR;
 private boolean displayRadius = DEFAULT_DISPLAY_RADIUS;

 /*
  * (non-Javadoc)
  *
  * @param context
  *
  * @see cn.limc.androidcharts.view.BaseChart#BaseChart(Context)
  */
 public PieChart(Context context) {
  super(context);
 }

 /*
  * (non-Javadoc)
  *
  * @param context
  *
  * @param attrs
  *
  * @param defStyle
  *
  * @see cn.limc.androidcharts.view.BaseChart#BaseChart(Context,
  * AttributeSet, int)
  */
 public PieChart(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
 }

 /*
  * (non-Javadoc)
  *
  * @param context
  *
  * @param attrs
  *
  * @see cn.limc.androidcharts.view.BaseChart#BaseChart(Context,
  * AttributeSet)
  */
 public PieChart(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

 /*
  * (non-Javadoc)
  *
  * <p>Called when is going to draw this chart</p>
  * <p>銉併儯銉笺儓銈掓浉銇忓墠銆併儭銈姐儍銉夈倰鍛笺伓</p>
  * <p>缁樺埗鍥捐〃鏃惰皟鐢/p>
  *
  * @param canvas
  *
  * @see android.view.View#onDraw(android.graphics.Canvas)
  */
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);

  // get safe rect
  int rect = super.getWidth() > super.getHeight() ? super.getHeight()
    : super.getWidth();

  // calculate radius length
  radiusLength = (int) ((rect / 2f) * 0.90);

  // calculate position
  position = new Point((int) (getWidth() / 2f), (int) (getHeight() / 2f));

  // draw this chart
  drawCircle(canvas);

  // draw data on chart
  drawData(canvas);
 }

 protected void drawCircle(Canvas canvas) {

  Paint mPaintCircleBorder = new Paint();
  mPaintCircleBorder.setColor(Color.WHITE);
  mPaintCircleBorder.setStyle(Style.STROKE);
  mPaintCircleBorder.setStrokeWidth(2);
  mPaintCircleBorder.setAntiAlias(true);

  // draw a circle
  canvas.drawCircle(position.x, position.y, radiusLength,
    mPaintCircleBorder);
 }

 protected void drawData(Canvas canvas) {
  if (null != data) {
   // sum all data's value
   float sum = 0;
   for (int i = 0; i < data.size(); i++) {
    sum = sum + data.get(i).getValue();
   }

   Paint mPaintFill = new Paint();
   mPaintFill.setStyle(Style.FILL);
   mPaintFill.setAntiAlias(true);

   Paint mPaintBorder = new Paint();
   mPaintBorder.setStyle(Style.STROKE);
   mPaintBorder.setColor(radiusColor);
   mPaintBorder.setAntiAlias(true);

   int offset = -90;
   // draw arcs of every piece
   for (int j = 0; j < data.size(); j++) {
    TitleValueColorEntity e = data.get(j);

    // get color
    mPaintFill.setColor(e.getColor());

    RectF oval = new RectF(position.x - radiusLength, position.y
      - radiusLength, position.x + radiusLength, position.y
      + radiusLength);
    int sweep = Math.round(e.getValue() / sum * 360f);
    canvas.drawArc(oval, offset, sweep, true, mPaintFill);
    canvas.drawArc(oval, offset, sweep, true, mPaintBorder);
    offset = offset + sweep;
   }

   float sumvalue = 0f;
   for (TitleValueColorEntity e : data) {
    float value = e.getValue();
    sumvalue = sumvalue + value;
    float rate = (sumvalue - value / 2) / sum;
    mPaintFill.setColor(Color.BLUE);

    // percentage
    float percentage = (int) (value / sum * 10000) / 100f;

    float offsetX = (float) (position.x - radiusLength * 0.5
      * Math.sin(rate * -2 * Math.PI));
    float offsetY = (float) (position.y - radiusLength * 0.5
      * Math.cos(rate * -2 * Math.PI));

    Paint mPaintFont = new Paint();
    mPaintFont.setColor(Color.WHITE);
    mPaintFont.setTextSize(MyUtils.sp2px(getContext(), 15));
    mPaintFont.setAntiAlias(true);
    mPaintFont.setStrokeWidth(5);

    // draw titles
    String title = e.getTitle();
    float realx = 0;
    float realy = 0;

    // TODO title position
    if (offsetX < position.x) {
     realx = offsetX - mPaintFont.measureText(title) - 5;
    } else if (offsetX > position.x) {
     realx = offsetX + 5;
    } else if (offsetX == position.x) {
     realx = offsetX - (mPaintFont.measureText(title)/2);
    }

    if (offsetY >= position.y) {
     if (value / sum < 0.2f) {
      realy = offsetY + 10;
     } else {
      realy = offsetY + 5;
     }
    } else if (offsetY < position.y) {
     if (value / sum < 0.2f) {
      realy = offsetY - 10;
     } else {
      realy = offsetY + 5;
     }
    }

    if(percentage != 0.0f) {
     canvas.drawText(title, realx, realy, mPaintFont);
     canvas.drawText(String.valueOf((int)value) + "min", realx, realy + MyUtils.sp2px(getContext(), 15), mPaintFont);
     canvas.drawText(String.valueOf(percentage) + "%", realx,
       realy + MyUtils.sp2px(getContext(), 30), mPaintFont);
    }
   }
  }
 }

 /**
  * @return the data
  */
 public List<TitleValueColorEntity> getData() {
  return data;
 }

 /**
  * @param data
  *            the data to set
  */
 public void setData(List<TitleValueColorEntity> data) {
  this.data = data;
 }

 /**
  * @return the title
  */
 public String getTitle() {
  return title;
 }

 /**
  * @param title
  *            the title to set
  */
 public void setTitle(String title) {
  this.title = title;
 }

 /**
  * @return the position
  */
 public Point getPosition() {
  return position;
 }

 /**
  * @param position
  *            the position to set
  */
 public void setPosition(Point position) {
  this.position = position;
 }

 /**
  * @return the radiusLength
  */
 public int getRadiusLength() {
  return radiusLength;
 }

 /**
  * @param radiusLength
  *            the radiusLength to set
  */
 public void setRadiusLength(int radiusLength) {
  this.radiusLength = radiusLength;
 }

 /**
  * @return the radiusColor
  */
 public int getRadiusColor() {
  return radiusColor;
 }

 /**
  * @param radiusColor
  *            the radiusColor to set
  */
 public void setRadiusColor(int radiusColor) {
  this.radiusColor = radiusColor;
 }

 /**
  * @return the circleBorderColor
  */
 public int getCircleBorderColor() {
  return circleBorderColor;
 }

 /**
  * @param circleBorderColor
  *            the circleBorderColor to set
  */
 public void setCircleBorderColor(int circleBorderColor) {
  this.circleBorderColor = circleBorderColor;
 }

 /**
  * @return the displayRadius
  */
 public boolean isDisplayRadius() {
  return displayRadius;
 }

 /**
  * @param displayRadius
  *            the displayRadius to set
  */
 public void setDisplayRadius(boolean displayRadius) {
  this.displayRadius = displayRadius;
 }
}

---------------------------------分割线---------------------------------

/*
 * TitleValueEntity.java
 * Android-Charts
 *
 * Created by limc on 2011/05/29.
 *
 * Copyright 2011 limc.cn All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.nekocode.xuedao.piechart;

public class TitleValueEntity {
 private String title;
 private float value;
 
 public TitleValueEntity(String title, float value) {
  super();
  this.title = title;
  this.value = value;
 }

 public TitleValueEntity() {
  super();
 }

 /**
  * @return the title
  */
 public String getTitle() {
  return title;
 }

 /**
  * @param title
  *            the title to set
  */
 public void setTitle(String title) {
  this.title = title;
 }

 /**
  * @return the value
  */
 public float getValue() {
  return value;
 }

 /**
  * @param value
  *            the value to set
  */
 public void setValue(float value) {
  this.value = value;
 }
}

相关内容

    暂无相关文章