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

自定义 View ———— 折线图(重写 onDraw方法)

程序员文章站 2022-03-11 11:05:49
...

实现一个如下效果的折线图
自定义 View ———— 折线图(重写 onDraw方法)
这样的效果实现的方式很容易想到的就是重写 onDraw 方法,给定一组 float 值,分别画点、线,那么下面有颜色的阴影部分是用什么画呢,就用到了 Path, 一个点一个点相连成一个封闭的图形,便可画出这个图形。如果先画点,再画阴影部分,是会把点遮住一部分的,所以实现的时候先画完了阴影部分,再画线和点。不过这样子在 onDraw 方法里就有两个 for 循环,如果有好的办法欢迎提出。
下面直接贴出 View 的整个代码,代码不多

/**
 * @author hexiaosa
 * @date 2018/8/15
 */

public class CustomLineChart extends View {

    private int width; // 宽
    private int height; // 高
    private int pointNum; // 折点个数
    private int lineColor; // 折线颜色
    private int shadowColor; // 阴影颜色
    private float[] percents; // 百分比,可以理解为任务完成百分比
    private int itemWidth;
    private Path path; // 避免在 onDraw 方法内创建多个对象,所以在这里声明一个成员变量

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

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

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

        // 线颜色,阴影颜色,折点个数
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomLineChart);
        lineColor = typedArray.getColor(R.styleable.CustomLineChart_lineColor, Color.BLACK);
        shadowColor = typedArray.getColor(R.styleable.CustomLineChart_shadowColor, Color.BLACK);
        pointNum = typedArray.getInteger(R.styleable.CustomLineChart_pointNum, 0);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (pointNum == 0) {
            return;
        }
        if (percents == null || percents.length != pointNum) {
            return;
        }
        if (width == 0) {
            width = getMeasuredWidth();
        }
        if (height == 0) {
            height = getMeasuredHeight();
        }
        if (path == null) {
            path = new Path();
        }
        itemWidth = width/(pointNum-1);
        Paint paint = new Paint();
        paint.setStrokeWidth(5);
        // 阴影部分使用 Path 连接成一个封闭图形
        path.reset();
        path.moveTo(0, height);
        path.lineTo(0, height*(1-percents[0]));
        for (int i = 1; i < percents.length; i++) {
            // 连接阴影
            path.lineTo(itemWidth*i, height*(1-percents[i]));
        }
        path.lineTo(width, height);
        path.lineTo(0, height);
        paint.setColor(shadowColor);
        // 画阴影
        canvas.drawPath(path, paint);
        path.close();

        paint.setColor(lineColor);
        canvas.drawCircle(0, height*(1-percents[0]), 10, paint);
        for (int i = 1; i < percents.length; i++) {
            // 画线
            canvas.drawLine(itemWidth*(i-1), height*(1-percents[i-1]), itemWidth*i, height*(1-percents[i]), paint);
            // 画点
            canvas.drawCircle(itemWidth*i, height*(1-percents[i]), 10, paint);
        }

        canvas.save();
    }

    public void setPercents(float[] percents) {
        this.percents = percents;
        invalidate();
    }

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
    }

    public void setShadowColor(int shadowColor) {
        this.shadowColor = shadowColor;
    }

    public void setPointNum(int pointNum) {
        this.pointNum = pointNum;
    }
}


// attr.xml:
    <declare-styleable name="CustomLineChart">
        <attr name="lineColor" format="color"/>
        <attr name="shadowColor" format="color"/>
        <attr name="pointNum" format="integer"/>
    </declare-styleable>

使用示例:

CustomLineChart clc = (CustomLineChart) findViewById(R.id.clc);
// 必须设置,还有 pointNum 在布局或代码设置至少有一个地方设置,且 pointNum 需等于 percents.length
clc.setPercents(new float[]{0.5f, 0.3f, 0.4f, 0.7f, 0.1f, 0.2f, 0.6f, 0.8f, 0.9f, 1f});
相关标签: 自定义 View