Android自定义View实现简单的折线图、柱状图

来源:互联网 发布:北京市公共图书馆网络 编辑:程序博客网 时间:2024/05/19 04:28



首先说第一个柱状图,实现很简单。一个自定义View,重现里面的OnDraw方法。然后利用paint,canvas绘制带填充的长方形即可。每个长方形的X轴平方View的x轴即可,长方形的高度通过简单的计算即可得到。下面上柱状图代码

package com.hrules.charter.demo.widget;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.RectF;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;import android.view.animation.BounceInterpolator;import com.hrules.charter.demo.R;import java.util.Random;/** * 柱状图 * Created by 黄海 on 2017/4/17. */public class Histogram extends View implements View.OnClickListener {    int width, height;    Paint paintBar, paintText;    float[] values = new float[15];    float[] valuesTemp = new float[15];    int colorBackground = R.color.default_barBackgroundColor;//柱状背景    int[] colorBar = new int[]{R.color.lightBlue500, R.color.lightBlue400, R.color.lightBlue300};//柱状颜色    float maxY;    int barMarginLeft = 7;    int tagHeight = 45;//x和Y轴的数字    boolean anim;    boolean showLineXNums = true, showLineYNums = true;//展示X、Y轴的数字    int lineYNums = 5;//Y轴展示的格数    ValueAnimator valueAnimator;    public Histogram(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public Histogram(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        paintText = paintBar = new Paint();        paintBar.setAntiAlias(true);        paintText.setAntiAlias(true);        paintText.setTextSize(25);        paintText.setColor(getResources().getColor(colorBar[0]));        initValuesAndMaxY();        setOnClickListener(this);    }    private void initValuesAndMaxY() {        Random random = new Random();        for (int i = 0; i < values.length; i++) {            values[i] = random.nextFloat() * 100;        }        for (float i : values) {            maxY = maxY < i ? i : maxY;        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        width = getMeasuredWidth();        height = getMeasuredHeight();        int barWidth = (width - tagHeight) / values.length;        int j = 0;        if (!anim)            valuesTemp = values.clone();        for (int i = 0; i < valuesTemp.length; i++) {            RectF rect = new RectF();            rect.left = tagHeight + i * barWidth + barMarginLeft;            rect.top = (height - tagHeight) * (1 - 1.0f * valuesTemp[i] / maxY);            rect.right = rect.left + barWidth - barMarginLeft;            rect.bottom = height - tagHeight;            //draw the barBackground            paintBar.setColor(getResources().getColor(colorBackground));            canvas.drawRect(rect.left, 0, rect.right, rect.bottom, paintBar);            //paint the bar            j = j > colorBar.length - 1 ? 0 : j;            paintBar.setColor(getResources().getColor(colorBar[j++]));            canvas.drawRect(rect, paintBar);            if (showLineXNums) {                //draw x-coordinate num                float textWidth = paintText.measureText(String.valueOf(i));                float textLeft = rect.left + rect.width() / 2 - textWidth / 2;                canvas.drawText(String.valueOf(i), textLeft, height, paintText);            }        }        //draw y-coordinate num        if (showLineYNums) {            int avgHeight = (height - tagHeight) / lineYNums;            for (int i = 0; i < lineYNums; i++) {                float x = 0;                float y = (height - tagHeight) - avgHeight * (i + 1);                int valueY = (int) (maxY * (i + 1) / lineYNums);                // canvas写字是从x、y轴往右上写的                canvas.drawText(String.valueOf(valueY), x, y + 30, paintText);            }        }    }    @Override    public void onClick(View v) {        anim = true;        valueAnimator = ValueAnimator.ofFloat(0f, 1f);        valuesTemp = values.clone();        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                for (int i = 0; i < valuesTemp.length; i++) {                    //update valuesTemps                    float animatedValue = (float) animation.getAnimatedValue();                    valuesTemp[i] = maxY * animatedValue < values[i] ? maxY * animatedValue : values[i];                }                invalidate();            }        });//        valueAnimator.setInterpolator(new LinearInterpolator());        //落地回调效果        valueAnimator.setInterpolator(new BounceInterpolator());        valueAnimator.setDuration(2000l);        valueAnimator.start();    }}

实现比较简单,注释都有。最后说下onClick方法的作用:valuesTemp是原有柱状数据的副本,view点击后让valuesTemp的每个数据从maxY的最小百分比开始不断的增长,从而实现一个动态改变的动画效果,如下:


折线图运用的paint,canvas与path完成,计算每个点的位置和柱状图类似,折线图形成一个填充效果也简单就是path close一下,然后绘制close后的path就是。下面看源码

package com.hrules.charter.demo.widget;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PointF;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;import com.hrules.charter.demo.R;import java.util.ArrayList;import java.util.List;import java.util.Random;/** * 折线图 * Created by 黄海 on 2017/4/18. */public class LineChart extends View {    Path path = new Path();    float[] values = new float[15];    float maxY;    Paint paintXy, paintLine;    int width, height;//view 宽高    public LineChart(Context context, @Nullable AttributeSet attrs) {        this(context, attrs, 0);    }    public LineChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initValuesAndMaxY();        paintXy = new Paint(Paint.ANTI_ALIAS_FLAG);        paintXy.setStyle(Paint.Style.STROKE);        paintXy.setStrokeWidth(6);        paintXy.setColor(getResources().getColor(R.color.lightBlue500));        paintLine = new Paint(Paint.ANTI_ALIAS_FLAG);        paintLine.setStyle(Paint.Style.FILL);        paintLine.setColor(getResources().getColor(R.color.colorPrimary));    }    private void initValuesAndMaxY() {        Random random = new Random();        for (int i = 0; i < values.length; i++) {            values[i] = random.nextFloat() * 100;            maxY = maxY < values[i] ? values[i] : maxY;        }    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        width = getMeasuredWidth();        height = getMeasuredHeight();        //每格宽度        int widthAvg = width / values.length;        //画x轴y轴        path.moveTo(0, 0);        path.lineTo(0, height);        path.lineTo(width, height);        canvas.drawPath(path, paintXy);        List<PointF> list = new ArrayList<>();        for (int i = 0; i < values.length; i++) {//收集坐标信息            PointF point = new PointF(widthAvg / 2 + i * widthAvg, 0);            point.set(widthAvg / 2 + i * widthAvg, (1 - values[i] / maxY) * height);            list.add(point);        }        //画线        path.reset();//清除 画x轴y轴而产生的闭合影响        path.moveTo(list.get(0).x, list.get(0).y);        for (int i = 1; i < values.length; i++) {            path.lineTo(list.get(i).x, list.get(i).y);//            path.cubicTo(ps.x, ps.y,(ps.x+pe.x)/2,(ps.y+pe.y)/2, pe.x, pe.y);//画三次贝塞尔曲线        }        canvas.drawPath(path, paintXy);        //折线图闭合        path.lineTo(list.get(values.length - 1).x, height);        path.lineTo(list.get(0).x, height);        path.close();        canvas.drawPath(path, paintLine);        //画点        for (int i = 0; i < values.length; i++) {            canvas.drawCircle(list.get(i).x, list.get(i).y, 9, paintLine);        }    }}



0 0
原创粉丝点击