首页 > 代码库 > Android 自定义View - 饼图

Android 自定义View - 饼图

  最近有看到一个自定义等分圆的View,自己尝试做了一个类似的,效果图如下图(1)所示:

技术分享

图(1)

  实现方法:自定义View-ColorCircle,需要的知道的值有圆的半径,等分个数以及扇形颜色。

    /**
     * 定义几种颜色
     */
    private static int COLOR[] = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW, Color.BLACK};
    /**
     * 圆等分默认数目
     */
    private static int DIV_SIZE = 3;

    private Paint mPaint;
   /** 
   * 圆默认半径
   */
private static final int DEFAULT_RADIUS = 200; private int mRadius = DEFAULT_RADIUS;
public ColorCircle(Context context) { this(context, null); } public ColorCircle(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public ColorCircle(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); mPaint.setStyle(Paint.Style.FILL); }

  在onMeasure中我们需要根据widthMeasureSpec & heightMeasureSpec重新计算ColorCircle View的尺寸以及圆的半径(因为默认圆的直径可能会大于View的高 or 宽)。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;
        int height;

        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = mRadius * 2 + getPaddingLeft() + getPaddingRight();
            if (widthMode == MeasureSpec.AT_MOST) {
                width = Math.min(width, widthSize);
            }
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = mRadius * 2 + getPaddingTop() + getPaddingBottom();
            if (heightMode == MeasureSpec.AT_MOST) {
                height = Math.min(width, heightSize);
            }
        }

        setMeasuredDimension(width, height);
        mRadius = (int) (Math.min(width - getPaddingLeft() - getPaddingRight(),
                height - getPaddingTop() - getPaddingBottom()) * 1.0f / 2);
    }

  最后在onDraw里通过canvas.drawArc()来绘制扇形。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//平移Canvas到屏幕中心,之后的绘制以中心点为初始点 canvas.translate((getWidth()
+ getPaddingLeft() - getPaddingRight()) / 2,
             (getHeight() + getPaddingTop() - getPaddingBottom()) / 2);
//定义一个RectF对象,表示扇形绘制区域 RectF oval = new RectF(-mRadius, -mRadius, mRadius, mRadius);
float firstAngle = 0.0f; float divideAngle = (360 * 1.0f) / DIV_SIZE;//根据DIV_SIZE来算每个扇形的角度 for (int i=0; i<DIV_SIZE; i++) { mPaint.setColor(COLOR[i]); canvas.drawArc(oval, (firstAngle + i * divideAngle), divideAngle, true, mPaint); } }

    public void setDivSize(int size){
        DIV_SIZE = size;
        invalidate();
    }

    public int getDivSize(){
        DIV_SIZE = size;
    }
 

  最后还预留了一个setDivSize()接口,方便自定义ColorCircle View动态变化扇形数目。我这里是通过Seekbar来动态切换DIV_SIZE。

    mColorCircle = (ColorCircle)findViewById(R.id.color_circle);
    mSeekBar = (SeekBar)findViewById(R.id.seek_bar);
    mSeekBar.setMax(4);//因为颜色数目原因,这里seekBar的最大值设置为了4。
int pro = mColorCircle.getSize(); mSeekBar.setProgress(
pro); mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { mColorCircle.setDivSize(progress + 1); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } });

  效果图如下:

技术分享 技术分享 技术分享 技术分享

Android 自定义View - 饼图