实现一个如图所示的控件,包括两部分,左边的饼状图和中间的两个小方块,及右边的两行文字

android 自定义prop_API

实现起来比较简单,只是一些绘图API的调用

核心代码在onDraw函数里边,,对静态控件进行绘制即可

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    /*饼状图的x坐标*/
    float centreX=  getWidth()/5;
    /*饼状图的y坐标*/
    float centreY= getHeight()/2;
    /*文字的大小*/
    float textSize=getHeight()/7;
    float width=(float)getWidth();
    float height=(float)getHeight();
    /*中间小正方形边长的一半*/
    float halfSmallRec =((float)getHeight())*3/70;
    percent =((float) mBigBallNumber)/(mBigBallNumber + mSmallBallNumber);
    /*求饼状图的半径*/
    radius= Math.min(getWidth() * 1 / 8, getHeight() * 10 / 35);
    /*构建一个正方形,饼状图是这个正方形的内切圆*/
    rectf=new RectF((int)(centreX-radius),(int)(centreY-radius),(int)(centreX+radius),(int)(centreY+radius));
    /*设置饼状图画笔的颜色,先绘制大球占的比例*/
    piePaint.setColor(mBigBallColor);
    /*The arc is drawn clockwise. An angle of 0 degrees correspond to the
    * geometric angle of 0 degrees (3 o'clock on a watch.)*/
    /*drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)*/
    /*绘制大球的扇形图,float startAngle起始角度的0度的位置在3点钟方向
    * 因此大球的扇形图要从12点钟开始绘制,所以起始角度为270度*/
    canvas.drawArc(rectf, 270, 360 * percent, true, piePaint);
    /*换种颜色,开始绘制小球占的饼状图*/
    piePaint.setColor(mSmallBallColor);
    /*起始角度就是12点钟加上360度乘以大球占的比例,12点钟转换为起始角度为270度*/
    canvas.drawArc(rectf, 270 + 360 * percent, 360 - 360 * percent, true, piePaint);
    /*颜色更改为大球的颜色*/
    piePaint.setColor(mBigBallColor);
    /*绘制上边的小方块,也就是大球的方块*/
    canvas.drawRect(width * 2 / 5 - halfSmallRec, height* 23/ 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height *23/ 60 + halfSmallRec, piePaint);
    /*更改画笔颜色为小球颜色*/
    piePaint.setColor(mSmallBallColor);
    /*绘制下边的小方块即小球的小方块*/
    canvas.drawRect(width * 2 / 5 - halfSmallRec, height * 37 / 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height * 37 / 60 + halfSmallRec, piePaint);
    /*开始绘制文字,先设置文字颜色*/
    textPaint.setColor(getResources().getColor(typedValue.resourceId));
    /*设置问题大小*/
    textPaint.setTextSize(textSize);
    /*大球数量*/
    String strBig = strBigBallName + mBigBallNumber;
    /*测量文字宽度*/
    float textBigWidth =textPaint.measureText(strBig);
    Paint.FontMetrics fontMetrics=textPaint.getFontMetrics();
    /*绘制上边大球数量*/
    canvas.drawText(strBig, width * 9 / 20 + textBigWidth / 2, height *23/ 60 - fontMetrics.top / 3, textPaint);
    /*小球数量*/
    String strSmall = strSmallBallName + mSmallBallNumber;
    /*测量文字宽度*/
    float textUnderWidth=textPaint.measureText(strSmall);
    /*绘制下边的小球数量*/
    canvas.drawText(strSmall,width*9/20+textUnderWidth/2,height*37/60-fontMetrics.top/3,textPaint);
    /*更改画笔颜色,开始绘制百分比*/
    textPaint.setColor(getResources().getColor(R.color.half_transparent));
    String strBigPercent =" ("+ mPercentBigBall +")";
    /*测量大球百分比文字宽度*/
    float bigPercent =textPaint.measureText(strBigPercent);
    /*drawText(String text, float x, float y, Paint paint)
    * 绘制文字的API,四个参数分别是文字内容,起始绘制x坐标,起始绘制y坐标,画笔
    * 以为设置了居中绘制,因此穿进去的xy坐标为文字的中心点*/
    canvas.drawText(strBigPercent, width * 9 / 20+ textBigWidth + bigPercent /2, height*23 / 60-fontMetrics.top*1/3, textPaint);
    /*同样的道理绘制小球的百分比*/
    String strSmallPercent =" ("+ mPercentSmallBall +")";
    float smallPercent =textPaint.measureText(strSmallPercent);
    canvas.drawText(strSmallPercent,width*9/20+textUnderWidth+ smallPercent /2,height*37/60-fontMetrics.top/3,textPaint);
}


Canvas 绘制文本时,使用FontMetrics对象,计算位置的坐标。


android 自定义prop_API_02

设置文字绘制以中心为起点开始绘制

textPaint.setTextAlign(Paint.Align.CENTER);

x的坐标好计算,y坐标需要按需使用FontMetrics几个属性即可

完整代码如下:

public class PieHalfView extends View {
    /*左边饼状图的画笔*/
    private Paint piePaint;
    /*右边文字的画笔*/
    private Paint textPaint;
    /*饼状图的半径*/
    private float radius;
    private RectF rectf;
    /*饼状图中第一个扇形占整个圆的比例*/
    private float percent;
    /*深浅两种颜色*/
    private int mBigBallColor, mSmallBallColor;
    /*大小球的数量*/
    private int mBigBallNumber;
    private int mSmallBallNumber;
    /*大小球所占的百分比*/
    private String mPercentBigBall;
    private String mPercentSmallBall;
    /*动态获取属性*/
    private TypedValue typedValue;
    /*中间的文字信息*/
    private String strBigBallName;
    private String strSmallBallName;

    public PieHalfView(Context context) {
        super(context);
        init(context);
    }

    public PieHalfView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public PieHalfView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    private void init(Context context) {
        /*设置饼状图画笔*/
        piePaint =new Paint();
        piePaint.setAntiAlias(true);
        piePaint.setStyle(Paint.Style.FILL);
        /*设置文字画笔*/
        textPaint=new Paint();
        textPaint.setStyle(Paint.Style.STROKE);
        textPaint.setAntiAlias(true);
        textPaint.setTextAlign(Paint.Align.CENTER);
        /*下边设置一些默认的值,如果调用者没有传值进来的话,用这些默认值*/
        mBigBallColor = 0xFF9CCA5D;
        mSmallBallColor =0xFF5F7048;
        /*TypedValue:Container for a dynamically typed data value. Primarily used with Resources for holding resource values.*/
        typedValue=new TypedValue();
        context.getTheme().resolveAttribute(R.attr.maintextclor,typedValue,true);
        mBigBallNumber =1;
        mSmallBallNumber =3;
        mPercentBigBall ="40%";
        mPercentSmallBall ="60%";
        strBigBallName =getResources().getString(R.string.big);
        strSmallBallName =getResources().getString(R.string.small);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /*饼状图的x坐标*/
        float centreX=  getWidth()/5;
        /*饼状图的y坐标*/
        float centreY= getHeight()/2;
        /*文字的大小*/
        float textSize=getHeight()/7;
        float width=(float)getWidth();
        float height=(float)getHeight();
        /*中间小正方形边长的一半*/
        float halfSmallRec =((float)getHeight())*3/70;
        percent =((float) mBigBallNumber)/(mBigBallNumber + mSmallBallNumber);
        /*求饼状图的半径*/
        radius= Math.min(getWidth() * 1 / 8, getHeight() * 10 / 35);
        /*构建一个正方形,饼状图是这个正方形的内切圆*/
        rectf=new RectF((int)(centreX-radius),(int)(centreY-radius),(int)(centreX+radius),(int)(centreY+radius));
        /*设置饼状图画笔的颜色,先绘制大球占的比例*/
        piePaint.setColor(mBigBallColor);
        /*The arc is drawn clockwise. An angle of 0 degrees correspond to the
        * geometric angle of 0 degrees (3 o'clock on a watch.)*/
        /*drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint)*/
        /*绘制大球的扇形图,float startAngle起始角度的0度的位置在3点钟方向
        * 因此大球的扇形图要从12点钟开始绘制,所以起始角度为270度*/
        canvas.drawArc(rectf, 270, 360 * percent, true, piePaint);
        /*换种颜色,开始绘制小球占的饼状图*/
        piePaint.setColor(mSmallBallColor);
        /*起始角度就是12点钟加上360度乘以大球占的比例,12点钟转换为起始角度为270度*/
        canvas.drawArc(rectf, 270 + 360 * percent, 360 - 360 * percent, true, piePaint);
        /*颜色更改为大球的颜色*/
        piePaint.setColor(mBigBallColor);
        /*绘制上边的小方块,也就是大球的方块*/
        canvas.drawRect(width * 2 / 5 - halfSmallRec, height* 23/ 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height *23/ 60 + halfSmallRec, piePaint);
        /*更改画笔颜色为小球颜色*/
        piePaint.setColor(mSmallBallColor);
        /*绘制下边的小方块即小球的小方块*/
        canvas.drawRect(width * 2 / 5 - halfSmallRec, height * 37 / 60 - halfSmallRec, width * 2 / 5 + halfSmallRec, height * 37 / 60 + halfSmallRec, piePaint);
        /*开始绘制文字,先设置文字颜色*/
        textPaint.setColor(getResources().getColor(typedValue.resourceId));
        /*设置问题大小*/
        textPaint.setTextSize(textSize);
        /*大球数量*/
        String strBig = strBigBallName + mBigBallNumber;
        /*测量文字宽度*/
        float textBigWidth =textPaint.measureText(strBig);
        Paint.FontMetrics fontMetrics=textPaint.getFontMetrics();
        /*绘制上边大球数量*/
        canvas.drawText(strBig, width * 9 / 20 + textBigWidth / 2, height *23/ 60 - fontMetrics.top / 3, textPaint);
        /*小球数量*/
        String strSmall = strSmallBallName + mSmallBallNumber;
        /*测量文字宽度*/
        float textUnderWidth=textPaint.measureText(strSmall);
        /*绘制下边的小球数量*/
        canvas.drawText(strSmall,width*9/20+textUnderWidth/2,height*37/60-fontMetrics.top/3,textPaint);
        /*更改画笔颜色,开始绘制百分比*/
        textPaint.setColor(getResources().getColor(R.color.half_transparent));
        String strBigPercent =" ("+ mPercentBigBall +")";
        /*测量大球百分比文字宽度*/
        float bigPercent =textPaint.measureText(strBigPercent);
        /*drawText(String text, float x, float y, Paint paint)
        * 绘制文字的API,四个参数分别是文字内容,起始绘制x坐标,起始绘制y坐标,画笔
        * 以为设置了居中绘制,因此穿进去的xy坐标为文字的中心点*/
        canvas.drawText(strBigPercent, width * 9 / 20+ textBigWidth + bigPercent /2, height*23 / 60-fontMetrics.top*1/3, textPaint);
        /*同样的道理绘制小球的百分比*/
        String strSmallPercent =" ("+ mPercentSmallBall +")";
        float smallPercent =textPaint.measureText(strSmallPercent);
        canvas.drawText(strSmallPercent,width*9/20+textUnderWidth+ smallPercent /2,height*37/60-fontMetrics.top/3,textPaint);
    }
    public void setPercent(float percent1){
        this.percent =percent1;
        invalidate();
    }
    public void setColor(int mBigBallColor,int mSmallBallColor){
        this.mBigBallColor =mBigBallColor;
        this.mSmallBallColor =mSmallBallColor;
        invalidate();
    }

    public void setOverRunner(String bigPecent, String smallPercent, int big, int small,
                              int bigColor, int smallColor){
        this.mPercentBigBall = bigPecent;
        this.mPercentSmallBall = smallPercent;
        this.mBigBallNumber = big;
        this.mSmallBallNumber = small;
        this.mBigBallColor = bigColor;
        this.mSmallBallColor = smallColor;
        invalidate();
    }
}