1

嗨,我正在尝试绘制一个饼图并在每个饼图中居中放置一个位图,但我只是无法弄清楚数学。下面是我从教程中找到的大部分代码,但 TODO 下的 onDraw 方法中的内容是我要添加的内容,因此我可以在饼图切片上绘制我的图标。任何关于它为什么不工作的帮助将不胜感激

public class PieChart extends View {

public interface OnSelectedLisenter{
    public abstract void onSelected(int iSelectedIndex);
}

private static String[] PIE_COLORS  = null;
private static int iColorListSize   = 0;
private OnSelectedLisenter onSelectedListener = null;
private static final String TAG = PieChart.class.getName();
public static final String ERROR_NOT_EQUAL_TO_100 = "NOT_EQUAL_TO_100";
private static final int DEGREE_360 = 360;
private Paint paintPieFill;
private Paint paintPieBorder;
private ArrayList<Float> alPercentage = new ArrayList<Float>();
private int iDisplayWidth, iDisplayHeight;
private int iSelectedIndex  = -1;
private int iCenterWidth    = 0;
private int iMargin         = 0;
private int iDataSize       = 0;
private RectF r             = null;
private float fDensity      = 0.0f;
private float fStartAngle   = 0.0f;
private float fEndAngle     = 0.0f;

public PieChart(Context context, AttributeSet attrs) {
    super(context, attrs);
    fnGetDisplayMetrics(context);
    PIE_COLORS = getResources().getStringArray(R.array.colors);
    iColorListSize = PIE_COLORS.length;
    iMargin = (int) fnGetRealPxFromDp(5);
    // used for paint circle
    paintPieFill = new Paint(Paint.ANTI_ALIAS_FLAG);
    paintPieFill.setStyle(Paint.Style.FILL);
    // used for paint border
    paintPieBorder = new Paint(Paint.ANTI_ALIAS_FLAG);
    paintPieBorder.setStyle(Paint.Style.STROKE);
    paintPieBorder.setStrokeWidth(fnGetRealPxFromDp(3));
    paintPieBorder.setColor(Color.WHITE);
}

// set listener
public void setOnSelectedListener(OnSelectedLisenter listener){
    this.onSelectedListener = listener;
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for (int i = 0; i < iDataSize; i++) {
        if (i>=iColorListSize){
            paintPieFill.setColor(Color.parseColor(PIE_COLORS[i%iColorListSize]));
        }else{
            paintPieFill.setColor(Color.parseColor(PIE_COLORS[i]));
        }
        fEndAngle = alPercentage.get(i);
        fEndAngle = fEndAngle / 100 * DEGREE_360;
        canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieFill);
        //TODO add icon to center of pie slice
        float x = (float) ((r.right /4)*Math.cos(Math.toRadians(fStartAngle)));
        float y = (float) ((r.right /4)*Math.sin(Math.toRadians(fStartAngle)));
        x += getWidth()/2;
        y += getHeight()/2;
        canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), x, y, paintPieFill);
        fStartAngle = fStartAngle + fEndAngle;
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    iDisplayWidth = MeasureSpec.getSize(widthMeasureSpec);
    iDisplayHeight = MeasureSpec.getSize(heightMeasureSpec);
    if (iDisplayWidth>iDisplayHeight){
        iDisplayWidth = iDisplayHeight;
    }
    iCenterWidth = iDisplayWidth / 2; 
    int iR = iCenterWidth-iMargin;
    if (r == null) {
        r = new RectF(iCenterWidth-iR,  // top
                iCenterWidth-iR,        // left
                iCenterWidth+iR,        // rights
                iCenterWidth+iR);       // bottom
    }
    setMeasuredDimension(iDisplayWidth, iDisplayWidth);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    // get degree of the touch point
    double dx = Math.atan2(event.getY() - iCenterWidth, event.getX() - iCenterWidth);
    float fDegree = (float) (dx / (2 * Math.PI) * DEGREE_360);
    fDegree = (fDegree + DEGREE_360) % DEGREE_360;
    // get the percent of the selected degree
    float fSelectedPercent = fDegree * 100 / DEGREE_360;
    // check which pie was selected
    float fTotalPercent = 0;
    for (int i = 0; i < iDataSize; i++) {
        fTotalPercent += alPercentage.get(i);
        if (fTotalPercent > fSelectedPercent) {
            iSelectedIndex = i;
            break;
        }
    }
    if (onSelectedListener != null){
        onSelectedListener.onSelected(iSelectedIndex);
    }
    invalidate();
    return super.onTouchEvent(event);
}

private void fnGetDisplayMetrics(Context cxt){
    final DisplayMetrics dm = cxt.getResources().getDisplayMetrics();
    fDensity = dm.density;
}

private float fnGetRealPxFromDp(float fDp){
    return (fDensity!=1.0f) ? fDensity*fDp : fDp;
}

public void setAdapter(ArrayList<Float> alPercentage) throws Exception {
    this.alPercentage = alPercentage;
    iDataSize = alPercentage.size();
    float fSum = 0;
    for (int i = 0; i < iDataSize; i++) {
        fSum+=alPercentage.get(i);
    }
    if (fSum!=100){
        Log.e(TAG,ERROR_NOT_EQUAL_TO_100);
        iDataSize = 0;
        throw new Exception(ERROR_NOT_EQUAL_TO_100);
    }   
}
}
4

1 回答 1

0

好吧,我发现这是我最后的 onDraw 方法,希望这对其他人有帮助

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < iDataSize; i++) {
            if (i>=iColorListSize){
                paintPieFill.setColor(Color.parseColor(PIE_COLORS[i%iColorListSize]));
            }else{
                paintPieFill.setColor(Color.parseColor(PIE_COLORS[i]));
            }
            fEndAngle = alPercentage.get(i);
            fEndAngle = fEndAngle / 100 * DEGREE_360;
            canvas.drawArc(r, fStartAngle, fEndAngle, true, paintPieFill);
            float angle = (fStartAngle + (fStartAngle+fEndAngle))/2;
            float x = (float) ((r.right /4)*Math.cos(Math.toRadians(angle)));
            float y = (float) ((r.right /4)*Math.sin(Math.toRadians(angle)));
            x += r.right/2;
            y += r.right/2;
            Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
            x -= bmp.getWidth()/2;
            y -= bmp.getHeight()/2;
            canvas.drawBitmap(bmp, x, y, paintPieFill);
            fStartAngle = fStartAngle + fEndAngle;
        }
    }
于 2013-08-28T19:43:58.130 回答