1. 程式人生 > >android自定義View&自定義ViewGroup(上)

android自定義View&自定義ViewGroup(上)

核心程式碼(程式碼中有詳細註釋):

public class CakeView extends View {
    //裝載的餅狀圓資料
    private List<CakeBean> beanList;
    //畫圓的矩形
    private RectF mRectF;
    //右邊的小矩形
    private RectF iRectF;
    private Paint mPaint;
    private int mRWidth, mRHeight;
    private float rotateDegree;//每個圓弧的起始角度
    private float sumValue = 0;//所有值的和
    private float diameter;//圓的直徑
    private float textY;//繪製文字的Y座標
    private float mRectHeight = 40;//矩形高度
    private float mRectWidth = 80;//矩形寬度
    private float mMargin = 40;//矩形和圓的距離
    private Context mContext;

    public CakeView(Context context) {
        //CakeView cakeView=new CakeView(context);
        // 在程式碼中new CakeView()會呼叫這個建構函式
        this(context, null);
    }

    public CakeView(Context context, AttributeSet attrs) {
        //InflateLayoutManager時會呼叫這個建構函式
        this(context, attrs, 0);
    }

    public CakeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        init();
   }

    private void init() {
        beanList = new ArrayList<>();
        mRectF = new RectF();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //MeasureSpec封裝了父View傳遞給子View的佈局要求
        //寬度測量模式
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        //寬度測量值
        int wSize = MeasureSpec.getSize(widthMeasureSpec);
        //高度測量模式
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        //高度測量值
        int hSize = MeasureSpec.getSize(heightMeasureSpec);
        switch (wMode) {
            case MeasureSpec.EXACTLY:
                //相當於match_parent或者一個具體值
                mRWidth = wSize;
                break;
            case MeasureSpec.AT_MOST:
                // 相當於wrap_content ,需要手動測量大小,這裡先寫死大小
                mRWidth = (int) DpUtil.dp2px(mContext, 400f);
                break;
            case MeasureSpec.UNSPECIFIED:
                //很少會用到
                break;
            default:
                break;
        }
        switch (hMode) {
            case MeasureSpec.EXACTLY:
                //相當於match_parent或者一個具體值
                mRHeight = hSize;
                break;
            case MeasureSpec.AT_MOST:
               // 相當於wrap_content ,需要手動測量大小,這裡先寫死大小
                mRHeight = (int) DpUtil.dp2px(mContext, 200f);
                break;
            case MeasureSpec.UNSPECIFIED:
                //很少會用到
                break;
            default:
                break;
        }
        //儲存測量好的寬和高
        setMeasuredDimension(wSize, hSize);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        diameter = Math.min(mRWidth, mRHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //設定圓形繪製的範圍
        mRectF.set(0, 0, diameter, diameter);
        //畫布中心X座標向右移動(控制元件寬度-圓直徑)之差的八分之一的距離
        //畫布中心Y座標向下移動(控制元件寬度-圓直徑)之差的二分之一的距離
        canvas.translate((mRWidth - diameter) / 8, (mRHeight - diameter) / 2);
        if (beanList.size() > 0 && Float.compare(sumValue, 0.0f) != 0) {
            for (int i = 0; i < beanList.size(); i++) { 
               CakeBean bean = beanList.get(i);
                //畫圓弧
                mPaint.setColor(bean.mColor);
                canvas.drawArc(mRectF, rotateDegree, bean.degree, true, mPaint);
                rotateDegree += bean.degree;
                //畫矩形和文字
                drawRectAndText(canvas, bean);
            }
        }
    }

    private void drawRectAndText(Canvas canvas, CakeBean bean) {
        iRectF = new RectF();
        //設定畫矩形的範圍
        float left = diameter + mMargin;
        float right = diameter + mMargin + mRectWidth;
        float bottom = textY + mRectHeight;
        iRectF.set(left, textY, right, bottom);
        canvas.drawRect(iRectF, mPaint);
        //設定顏色
        mPaint.setColor(Color.BLACK);
        //設定文字大小
        mPaint.setTextSize(30);
        //畫文字
        canvas.drawText(bean.name + "(" + new DecimalFormat(".00").format(bean.value / sumValue * 100) + "%)", right + 10, textY + 30, mPaint);
        textY += mRectHeight;
    }

    /**
     * 餅狀圖新增資料
     * 
    * @param beans CakeBean資料
     */
    public void setData(List<CakeBean> beans) {
        if (beans == null || beans.size() <= 0) return;
        for (int i = 0; i < beans.size(); i++) {
            CakeBean bean = beans.get(i);
            sumValue += bean.value;
        }
        for (int i = 0; i < beans.size(); i++) {
            CakeBean bean = beans.get(i);
            bean.degree = bean.value / sumValue * 360;
            beanList.add(bean);
        }
        invalidate();
    }

    /**
     * @param startDegree 設定起始角度
     */    public void setStartDegree(float startDegree) {
        this.rotateDegree = startDegree;
        invalidate();
    }}

自定義View的使用先到這裡,自定義ViewGroup接下篇