上一篇主要是记录了如何实现简单的折线图,支持点击弹出提示;这篇主要是实现另外一种图表–饼状图。
for (int i = 0; i < numbers.size(); i++) { if (i == numbers.size() - 1) { sweepAngle = 360 - startAngle; } else { sweepAngle = (int) (numbers.get(i) * 1.0f / total * 360); }
看上边的代码,为什么最后一个我没有用最后的item值去除于总值,而是通过用360减去其他所有角度的总和呢?因为,我们使用除法进行计算,会很有可能得到带小数的结果,但画扇形接受的角度都是int型,这就会产生误差,导致最后不能刚好画满整个圆。于是需要采用这种方式来避免
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX();
float y = event.getY();
int radius = 0;
// 第一象限
if (x >= getMeasuredWidth() / 2 && y >= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((y - getMeasuredHeight() / 2) * 1.0f
/ (x - getMeasuredWidth() / 2)) * 180 / Math.PI);
}
// 第二象限
if (x <= getMeasuredWidth() / 2 && y >= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((getMeasuredWidth() / 2 - x)
/ (y - getMeasuredHeight() / 2))
* 180 / Math.PI + 90);
}
// 第三象限
if (x <= getMeasuredWidth() / 2 && y <= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((getMeasuredHeight() / 2 - y)
/ (getMeasuredWidth() / 2 - x))
* 180 / Math.PI + 180);
}
// 第四象限
if (x >= getMeasuredWidth() / 2 && y <= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((x - getMeasuredWidth() / 2)
/ (getMeasuredHeight() / 2 - y))
* 180 / Math.PI + 270);
}
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
if (point.x <= radius && point.y >= radius) {
select = i;
// Toast.makeText(context, "点击了" + point,
// Toast.LENGTH_SHORT)
// .show();
invalidate();
return true;
}
}
return true;
}
return super.onTouchEvent(event);
}
public class CircleChartView extends View {
private List<Double> numbers;
private List<Point> points;
private double total;
private RectF normalOval;
private RectF selectOval;
private Paint paint;
private Context context;
public static final int[] colors = { android.R.color.holo_blue_light,
android.R.color.holo_green_light, android.R.color.holo_red_light,
android.R.color.holo_orange_light, android.R.color.holo_purple };
public CircleChartView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
numbers = new ArrayList<Double>();
normalOval = new RectF();
selectOval = new RectF();
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Style.FILL);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST
|| heightMode == MeasureSpec.AT_MOST) {
width = 400;
height = 400;
}
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
normalOval.left = (float) (getMeasuredWidth() * 0.1);
normalOval.top = (float) (getMeasuredHeight() * 0.1);
normalOval.right = (float) (getMeasuredWidth() * 0.9);
normalOval.bottom = (float) (getMeasuredHeight() * 0.9);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!numbers.isEmpty()) {
int startAngle = 0;
int sweepAngle = 0;
for (int i = 0; i < numbers.size(); i++) {
if (i == numbers.size() - 1) {
sweepAngle = 360 - startAngle;
} else {
sweepAngle = (int) (numbers.get(i) * 1.0f / total * 360);
}
if (select >= 0 && i == select) {
selectOval.left = (float) (getMeasuredWidth() * 0.1);
selectOval.top = (float) (getMeasuredHeight() * 0.1);
selectOval.right = (float) (getMeasuredWidth() * 0.9);
selectOval.bottom = (float) (getMeasuredHeight() * 0.9);
Point point = points.get(select);
int middle = (point.x + point.y) / 2;
if (middle <= 90) {
int top = (int) (Math.sin(Math.toRadians(middle)) * 15);
int left = (int) (Math.cos(Math.toRadians(middle)) * 15);
selectOval.left += left;
selectOval.right += left;
selectOval.top += top;
selectOval.bottom += top;
}
if (middle > 90 && middle <= 180) {
middle = 180 - middle;
int top = (int) (Math.sin(Math.toRadians(middle)) * 15);
int left = (int) (Math.cos(Math.toRadians(middle)) * 15);
selectOval.left -= left;
selectOval.right -= left;
selectOval.top += top;
selectOval.bottom += top;
}
if (middle > 180 && middle <= 270) {
middle = 270 - middle;
int left = (int) (Math.sin(Math.toRadians(middle)) * 15);
int top = (int) (Math.cos(Math.toRadians(middle)) * 15);
selectOval.left -= left;
selectOval.right -= left;
selectOval.top -= top;
selectOval.bottom -= top;
}
if (middle > 270 && middle <= 360) {
middle = 360 - middle;
int top = (int) (Math.sin(Math.toRadians(middle)) * 15);
int left = (int) (Math.cos(Math.toRadians(middle)) * 15);
selectOval.left += left;
selectOval.right += left;
selectOval.top -= top;
selectOval.bottom -= top;
}
paint.setColor(getResources().getColor(colors[i]));
canvas.drawArc(selectOval, startAngle, sweepAngle, true,
paint);
} else {
paint.setColor(getResources().getColor(colors[i]));
canvas.drawArc(normalOval, startAngle, sweepAngle, true,
paint);
}
points.get(i).x = startAngle;
points.get(i).y = startAngle + sweepAngle;
startAngle += sweepAngle;
}
}
}
public void setNumbers(List<Double> numbers) {
this.numbers.clear();
this.numbers.addAll(numbers);
points = new ArrayList<Point>();
for (Double item : numbers) {
total += item;
Point point = new Point();
points.add(point);
}
invalidate();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
float x = event.getX();
float y = event.getY();
int radius = 0;
// 第一象限
if (x >= getMeasuredWidth() / 2 && y >= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((y - getMeasuredHeight() / 2) * 1.0f
/ (x - getMeasuredWidth() / 2)) * 180 / Math.PI);
}
// 第二象限
if (x <= getMeasuredWidth() / 2 && y >= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((getMeasuredWidth() / 2 - x)
/ (y - getMeasuredHeight() / 2))
* 180 / Math.PI + 90);
}
// 第三象限
if (x <= getMeasuredWidth() / 2 && y <= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((getMeasuredHeight() / 2 - y)
/ (getMeasuredWidth() / 2 - x))
* 180 / Math.PI + 180);
}
// 第四象限
if (x >= getMeasuredWidth() / 2 && y <= getMeasuredHeight() / 2) {
radius = (int) (Math.atan((x - getMeasuredWidth() / 2)
/ (getMeasuredHeight() / 2 - y))
* 180 / Math.PI + 270);
}
for (int i = 0; i < points.size(); i++) {
Point point = points.get(i);
if (point.x <= radius && point.y >= radius) {
select = i;
// Toast.makeText(context, "点击了" + point,
// Toast.LENGTH_SHORT)
// .show();
invalidate();
return true;
}
}
return true;
}
return super.onTouchEvent(event);
}
private int select = -1;
}
源码下载