先上圖
普通效果
點選效果,點選之後會放大半徑
實作百分比圓餅,整體步驟分為
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<CakeBean> 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<CakeBean> cakes){
this.mCakeBean = cakes;
invalidate();
}
}
以上就是核心自定義類的代碼,主要難點在于點選換圓弧的半徑,可以重點看一下代碼,實作的邏輯是根據數學公式x平方 + y平方 < 半徑的平方,那麼判斷是在圓上;第二步如果判斷在圓上的話,運用region知識,求交集區域(盡可能把交集區域加大)