先上图
普通效果
点击效果,点击之后会放大半径
实现百分比圆饼,整体步骤分为
1.先根据数据集占的百分比画圆弧,使用不同颜色,很简单
2.然后设置点击重绘圆饼,判断点击区域在不在圆上,如果在圆上,那么在具体的哪个圆弧上面
上代码:直接拿去使用即可
package com.cnki.roundcake;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RegionIterator;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
/**
* 百分比圆饼图
* Created by liweidong on 2019/12/2.
*/
public class RoundCake extends View{
//数据集
private ArrayList mCakeBean;
private Paint paint;
//半径
private int radius = 150;
private RectF rectF;
private RectF rectFTouch;
//画百分比时每次的开始角度
private float startRadius;
private float mCurX;
private float mCurY;
private Paint regionPaint;
public RoundCake(Context context) {
super(context);
init();
}
public RoundCake(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RoundCake(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* 初始化
*/
private void init(){
mCurX = -1;
mCurY = -1;
startRadius = 0;
paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(5);
//初始化圆饼矩形
rectF = new RectF(20,20, radius * 2, radius * 2);
rectFTouch = new RectF(0,0, radius * 2 + 20, radius * 2 + 20);
regionPaint = new Paint();
regionPaint.setColor(Color.WHITE);
regionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
regionPaint.setStrokeWidth(2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
startRadius = 0;
//首先判断是否在圆内
if (mCurX != -1){
if ( ((mCurX - radius) * (mCurX - radius) + (mCurY - radius) * (mCurY - radius)) < radius * radius){
//画饼图
for (int i = 0; i < mCakeBean.size(); i++){
paint.setColor(mCakeBean.get(i).getColor());
if (isContainPoint(canvas,i)){
canvas.drawArc(rectFTouch, startRadius + 5 , mCakeBean.get(i).getRadius() - 10, true, paint);
}else{
canvas.drawArc(rectF, startRadius, mCakeBean.get(i).getRadius(), true, paint);
}
startRadius += mCakeBean.get(i).getRadius();
}
return;
}
}
//画饼图
for (int i = 0; i < mCakeBean.size(); i++){
paint.setColor(mCakeBean.get(i).getColor());
canvas.drawArc(rectF, startRadius, mCakeBean.get(i).getRadius(), true, paint);
startRadius += mCakeBean.get(i).getRadius();
}
}
/**
* 判断圆弧区域内是否包含某点
* @param i
* @return
*/
private boolean isContainPoint(Canvas canvas,int i){
Path path = new Path();
path.moveTo(radius + 10, radius + 10);
if (i == 0){
path.lineTo(3 * radius + 10, radius + 10);
}else{
path.lineTo((float) (radius + 20 + 2*radius * Math.cos(Math.toRadians(startRadius))),
(float) (radius + 20 + 2*radius * Math.sin(Math.sin(Math.toRadians(startRadius)))));
}
path.lineTo((float) (radius + 20 + 2*radius * Math.cos(Math.toRadians(startRadius + mCakeBean.get(i).getRadius()))),
(float) (radius + 20 + 2*radius * Math.sin(Math.sin(Math.toRadians(startRadius + mCakeBean.get(i).getRadius())))));
path.close();
Region region = new Region();
region.setPath(path, new Region(new Rect(20, 20, radius * 2, radius * 2)));
/*RegionIterator regionIterator = new RegionIterator(region);
Rect rect = new Rect();
while (regionIterator.next(rect)){
canvas.drawRect(rect, paint);
}*/
return region.contains((int)mCurX, (int)mCurY);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mCurX = event.getX();
mCurY = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
invalidate();
return true;
case MotionEvent.ACTION_UP:
mCurX = -1;
mCurY = -1;
}
invalidate();
return super.onTouchEvent(event);
}
/**
* 设置数据给饼图
* @param cakes
*/
public void setCakes(ArrayList cakes){
this.mCakeBean = cakes;
invalidate();
}
}
以上就是核心自定义类的代码,主要难点在于点击换圆弧的半径,可以重点看一下代码,实现的逻辑是根据数学公式x平方 + y平方 < 半径的平方,那么判断是在圆上;第二步如果判断在圆上的话,运用region知识,求交集区域(尽可能把交集区域加大)