欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义View

程序员文章站 2022-05-30 20:26:04
...

自定义View的基本步骤是重写onMeasure方法及测量、onlayout方法及布局、ondraw方法及绘制,这三大步骤,但是当onMeasure方法被调用完后,控件大小发生变化会执行onSizeChanged,我们可以在这个方法里面做一下计算和配置

自定义View其实真正需要重写的方法是onMeasure和ondraw方法,在自定义ViewGroup的时候才需要onlayout方法,

画一个饼状图,里面有不同的占比,旁边会有个举行图显示占比

自定义View

看到这张图

第一,继承view,申明构造方法

public WxbView(Context context) {
    this(context, null);
}

public WxbView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
}

public WxbView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr); 
}

第二,重写onMeasure和ondraw、onSizeChanged方法

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int wmode = MeasureSpec.getMode(widthMeasureSpec);
    int wsize = MeasureSpec.getSize(widthMeasureSpec);
    int hmode = MeasureSpec.getMode(heightMeasureSpec);
    int hsize = MeasureSpec.getSize(heightMeasureSpec);
    mWidth=getSize(wmode,400f,wsize);
    mHeight=getSize(hmode,200f,hsize);
    //存储测量好的宽和高
    setMeasuredDimension(wsize,hsize);

}

private int getSize(int mode, float size, int msize) {
    int value = 0;
    switch (mode) {
        case MeasureSpec.EXACTLY:
            value = msize;
            break;
        case MeasureSpec.AT_MOST:
            value = DpUtil.dip2px(context, size);
            break;
        case MeasureSpec.UNSPECIFIED:
            break;
        default:
            break;
    }

    return value;

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mR=Math.min(mWidth,mHeight);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
   
}

第三,定义圆的直径、view的宽和高、绘制文字的坐标、矩形的宽度和高度、圆到矩形的距离等

private List<Bean> list;//饼状圆的数据

private RectF mRectF;//圆矩形

private RectF iRect;//右边的矩形

private Paint mPaint;//画笔

private int mWidth, mHeight;

private float rotateDegree;//每个圆的起始角度

private float sumValue;//所有值的和

private float mR;//圆的直径

private float textY;//绘制文字的Y坐标

private float mRectFHeight = 40;//矩形的高度

private float mRectFWidth = 80;//矩形的宽度

private float mMargin = 40;//矩形到圆的距离

private Context context;

第四,准备好Paint画笔,RectF矩形,并初始化

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

第五,绘制时计算每个区域绘制的起始位及具体绘制

//设置圆形绘制的范围
mRectF.set(0,0,mR,mR);
//画布中心X坐标向右移动(控件宽度-圆直径)之差的八分之一的距离
//画布中心Y坐标向下移动(控件高度-圆直径)之差的二分之一的距离
canvas.translate((mWidth-mR)/8,(mHeight-mR)/2);
if (list.size()>0&&Float.compare(sumValue,0.0f)!=0){
    for (int i=0;i<list.size();i++){
        Bean bean=list.get(i);
        //画圆弧
        mPaint.setColor(bean.getColor());
        canvas.drawArc(mRectF,rotateDegree,bean.getDegree(),true,mPaint);
        rotateDegree+=bean.getDegree();
        //画矩形和文字
        drawRectAntText(canvas,bean);
    }
}

矩形的起始位置及具体绘制

private void  drawRectAntText(Canvas canvas,Bean bean){
    iRect=new RectF();
    //设置画矩形的范围
    float left=mR+mMargin;
    float right=mR+mMargin+mRectFWidth;
    float bottom=textY+mRectFHeight;
    iRect.set(left,textY,right,bottom);
    canvas.drawRect(iRect,mPaint);
    //设置颜色
    mPaint.setColor(Color.BLACK);
    //设置文字大小
    mPaint.setTextSize(30);
    //画文字
    canvas.drawText(bean.getName()+"("+new DecimalFormat(".00").format(bean.getValue()/sumValue*100)+"%)",right+10,textY+30,mPaint);
    textY+=mRectFHeight;
}

第六,设置绘制数据

public void setData(List<Bean> list){

    if (list==null||list.size()<=0){
        return;
    }
    for (int i=0;i<list.size();i++){
        Bean bean=list.get(i);
        sumValue+=bean.getValue();
        bean.setDegree(bean.getValue());
    }
    for (int i=0;i<list.size();i++){
        Bean bean=list.get(i);
        bean.setDegree(bean.getValue()/sumValue*360);
        this.list.add(bean);
    }
    invalidate();
}

以上一个饼状图就绘制完成了

对应的bean

public class Bean {
    private String name;


    private int color;

    private float value;

    private float degree;

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getValue() {
        return value;
    }

    public void setValue(float value) {
        this.value = value;
    }

    public float getDegree() {
        return degree;
    }

    public void setDegree(float degree) {
        this.degree = degree;
    }
}

对应的自定义View

public class WxbView extends View {

    private List<Bean> list;//饼状圆的数据

    private RectF mRectF;//圆矩形

    private RectF iRect;//右边的矩形

    private Paint mPaint;//画笔

    private int mWidth, mHeight;

    private float rotateDegree;//每个圆的起始角度

    private float sumValue;//所有值的和

    private float mR;//圆的直径

    private float textY;//绘制文字的Y坐标

    private float mRectFHeight = 40;//矩形的高度

    private float mRectFWidth = 80;//矩形的宽度

    private float mMargin = 40;//矩形到圆的距离

    private Context context;


    public WxbView(Context context) {
        this(context, null);
    }

    public WxbView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WxbView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init();
    }

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int wmode = MeasureSpec.getMode(widthMeasureSpec);
        int wsize = MeasureSpec.getSize(widthMeasureSpec);
        int hmode = MeasureSpec.getMode(heightMeasureSpec);
        int hsize = MeasureSpec.getSize(heightMeasureSpec);
        mWidth=getSize(wmode,400f,wsize);
        mHeight=getSize(hmode,200f,hsize);
        //存储测量好的宽和高
        setMeasuredDimension(wsize,hsize);

    }

    private int getSize(int mode, float size, int msize) {
        int value = 0;
        switch (mode) {
            case MeasureSpec.EXACTLY:
                value = msize;
                break;
            case MeasureSpec.AT_MOST:
                value = DpUtil.dip2px(context, size);
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
            default:
                break;
        }

        return value;

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mR=Math.min(mWidth,mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //设置圆形绘制的范围
        mRectF.set(0,0,mR,mR);
        //画布中心X坐标向右移动(控件宽度-圆直径)之差的八分之一的距离
        //画布中心Y坐标向下移动(控件高度-圆直径)之差的二分之一的距离
        canvas.translate((mWidth-mR)/8,(mHeight-mR)/2);
        if (list.size()>0&&Float.compare(sumValue,0.0f)!=0){
            for (int i=0;i<list.size();i++){
                Bean bean=list.get(i);
                //画圆弧
                mPaint.setColor(bean.getColor());
                canvas.drawArc(mRectF,rotateDegree,bean.getDegree(),true,mPaint);
                rotateDegree+=bean.getDegree();
                //画矩形和文字
                drawRectAntText(canvas,bean);
            }
        }
    }

    private void  drawRectAntText(Canvas canvas,Bean bean){
        iRect=new RectF();
        //设置画矩形的范围
        float left=mR+mMargin;
        float right=mR+mMargin+mRectFWidth;
        float bottom=textY+mRectFHeight;
        iRect.set(left,textY,right,bottom);
        canvas.drawRect(iRect,mPaint);
        //设置颜色
        mPaint.setColor(Color.BLACK);
        //设置文字大小
        mPaint.setTextSize(30);
        //画文字
        canvas.drawText(bean.getName()+"("+new DecimalFormat(".00").format(bean.getValue()/sumValue*100)+"%)",right+10,textY+30,mPaint);
        textY+=mRectFHeight;
    }
    public void setData(List<Bean> list){

        if (list==null||list.size()<=0){
            return;
        }
        for (int i=0;i<list.size();i++){
            Bean bean=list.get(i);
            sumValue+=bean.getValue();
            bean.setDegree(bean.getValue());
        }
        for (int i=0;i<list.size();i++){
            Bean bean=list.get(i);
            bean.setDegree(bean.getValue()/sumValue*360);
            this.list.add(bean);
        }
        invalidate();
    }
}
相关标签: Android