折线图的绘制

最近在做股票相关的项目,避免不了折线图,在这里温习一下写法,都是很简单的东西。


先看一下效果图



然后贴代码:



public class FTenBrokenLineView extends View {
    public int XPoint = DipUtil.dip2px(40);    //原点的X坐标
    public int YPoint = DipUtil.dip2px(210);     //原点的Y坐标
    public int XScale = 55;     //X的刻度长度
    public int YScale = 40;     //Y的刻度长度
    public int XLength = 300;        //X轴的长度
    public int YLength = 210;        //Y轴的长度
    public String[] XLabel;    //X的刻度
    public String[] YLabel;    //Y的刻度
    public String[] Data;      //数据
    public String Title;    //显示的标题

    private Context context;
    private Paint axisPaint;// 轴线
    private Paint dataPaint;// 数据线
    private Paint yTextPaint;// 文字的笔
    private Paint xTextPaint;
    private Paint titlePaint; // Y轴顶部的提示
    private Paint annulusPaint; // 数据圆环
    private Paint paint;
    private Path path;
    Paint paint1;

    private float radius = DipUtil.dip2px(4);// 数据圆环的半径

    public FTenBrokenLineView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public FTenBrokenLineView(Context context) {
        super(context);
        this.context = context;
        init();
    }

    private void init() {
        XLength = DataManager.getInstance(context).getDeviceWidth(context) - DipUtil.dip2px(70);// 这个是把屏幕的宽度减去两边的间距的和
        YLength = DipUtil.dip2px(190);
    }

    /**
     * 为折线图设置数据
     *
     * @param XLabels  x的刻度
     * @param YLabels  y的刻度
     * @param AllData  传入的数据
     */
    public void setInfo(String[] XLabels, String[] YLabels, String[] AllData) {
        XLabel = XLabels;
        YLabel = YLabels;
        Data = AllData;

        XScale = XLength / (XLabel.length - 1);
        YScale = YLength / YLabel.length;// 因为Y轴方向上第0个点没有数据,所以要特殊处理
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);//重写onDraw方法
        initPaint();
        canvas.drawLine(XPoint, YPoint, XPoint + XLength, YPoint, axisPaint);   //X轴
        canvas.drawLine(XPoint, YPoint - YLength, XPoint, YPoint, axisPaint);   //画Y轴

        for (int i = 1; i <= YLabel.length; i++) {
            canvas.drawLine(XPoint, YPoint - i * YScale, XPoint + XLength, YPoint - i * YScale, axisPaint);  //画横着方向每一个刻度,长度是X轴的长度
            int j = i - 1;// 因为Y轴方向上第0个点没有数据,这里特殊处理
            canvas.drawText(YLabel[j], XPoint - DipUtil.dip2px(25), YPoint - i * YScale + DipUtil.dip2px(3), yTextPaint);  //文字
        }

        for (int i = 0; i < XLabel.length; i++) {
            canvas.drawLine(XPoint + i * XScale, YPoint, XPoint + i * XScale, YPoint - YLength, axisPaint);  //画X轴方向刻度

            if (i > 0 && YCoord(Data[i - 1]) != -999 && YCoord(Data[i]) != -999) {  //保证有效数据
                paint1 = new Paint();
                paint1.setAntiAlias(true);
                paint1.setStyle(Paint.Style.FILL);
                paint1.setColor(0x153ea3ff);// 这个颜色就蓝色不透明8%
                path = new Path();// 以每一个间距绘制它的路径,然后填充颜色。
                path.moveTo(XPoint + (i - 1) * XScale, YCoord(Data[i - 1]));
                path.lineTo(XPoint + i * XScale, YCoord(Data[i]));
                path.lineTo(XPoint + i * XScale, YPoint);
                path.lineTo(XPoint + (i - 1) * XScale, YPoint);
                path.close();
                canvas.drawPath(path, paint1);// 这里是绘制阴影效果

                canvas.drawLine(XPoint + (i - 1) * XScale, YCoord(Data[i - 1]), XPoint + i * XScale, YCoord(Data[i]), dataPaint);// 绘制数据线
            }
        }

        // 循环X轴上的数据
        for (int i = 0; i < XLabel.length; i++) {
            // 这里是计算X轴上的标示长度,因为是分为两行,所以分割为2015 和 三季度,然后计算长度
            String str1 = XLabel[i].substring(0, 4);
            float strwid1 = xTextPaint.measureText(str1);
            String str2 = XLabel[i].substring(4);
            float strwid2 = xTextPaint.measureText(str2);

            canvas.drawText(str1, (XPoint + i * XScale) - strwid1 / 2, YPoint + DipUtil.dip2px(15), xTextPaint);// 绘制X轴上的刻度数据,第一行2015
            canvas.drawText(str2, (XPoint + i * XScale) - strwid2 / 2, YPoint + DipUtil.dip2px(30), xTextPaint);// 绘制X轴上的刻度数据,第二行三季度
            str1 = null;
            str2 = null;

            canvas.drawCircle(XPoint + i * XScale, YCoord(Data[i]), radius, annulusPaint);// 绘制数据点,是一个圆环
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(context.getResources().getColor(R.color.background_gray));
            canvas.drawCircle(XPoint + i * XScale, YCoord(Data[i]), radius * 2 / 3, paint);// 在圆环内部绘制一个圆,颜色为背景颜色
        }
    }

    private void initPaint() {
        axisPaint = new Paint();
        axisPaint.setStyle(Paint.Style.STROKE);
        axisPaint.setAntiAlias(true);
        axisPaint.setStrokeWidth(DipUtil.dip2px(1));
        axisPaint.setColor(context.getResources().getColor(R.color.line));

        dataPaint = new Paint();
        dataPaint.setStyle(Paint.Style.STROKE);
        dataPaint.setAntiAlias(true);
        dataPaint.setStrokeWidth(radius / 3);
        dataPaint.setColor(context.getResources().getColor(R.color.blue));

        annulusPaint = new Paint();
        annulusPaint.setAntiAlias(true);
        annulusPaint.setStrokeWidth(radius / 3);
        annulusPaint.setColor(context.getResources().getColor(R.color.blue));

        yTextPaint = new Paint();
        yTextPaint.setAntiAlias(true);
        yTextPaint.setColor(context.getResources().getColor(R.color.title_color));
        yTextPaint.setTextSize(context.getResources().getDimension(R.dimen.text_size_12));

        xTextPaint = new Paint();
        xTextPaint.setColor(context.getResources().getColor(R.color.text_gray));
        xTextPaint.setTextSize(context.getResources().getDimension(R.dimen.text_size_12));
        xTextPaint.setAntiAlias(true);

        titlePaint = new Paint();
        titlePaint.setAntiAlias(true);
        titlePaint.setColor(context.getResources().getColor(R.color.title_color));
        titlePaint.setTextSize(context.getResources().getDimension(R.dimen.text_size));
    }

    /**
     * 计算绘制时的Y坐标,无数据时返回-999
     * @param y0
     * @return
     */
    private float YCoord(String y0) {
        double y;
        double k;
        try {
            y = Double.parseDouble(y0);
        } catch (Exception e) {
            return -999;    //出错则返回-999
        }
        try {
            k = (YLength - YScale) / (Double.parseDouble(YLabel[YLabel.length - 1]) - Double.parseDouble(YLabel[0]));
            return (float) (((Double.parseDouble(YLabel[YLabel.length - 1]) - y) * k) + (YPoint - YLength));
        } catch (Exception e) {
        }
        return 0;
    }

}






这就是一个自定义的view,使用的时候就在xml文件中使用


<com.....FTenBrokenLineView
    android:id="@+id/flBrokenLine"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
上面是xml文件中的
 
下面是在代码中添加数据:
private FTenBrokenLineView flBrokenLine;

public String[] YLabel = {"0.5", "0.6", "0.7", "0.8", "0.9", "1.0", "1.1", "1.2"};    //X的刻度
public String[] XLabel = {"2014三季度", "2014年报", "2015一季度", "2015中报", "2015三季度"};    //Y的刻度
public String[] Data = {"0.9", "0.8", "1.1", "0.65", "0.92"};      //数据

flBrokenLine = ViewHolder.init(view, R.id.flBrokenLine);
flBrokenLine.setInfo(XLabel, YLabel, Data);

自定义的view代码写的很乱,因为中间写的时候会有覆盖问题,所以为了能显示出效果,就写的很随便了,也不是很通用。


diputil.dip2px方法就是px和dp转换的方法。


DataManager.getInstance(context).getDeviceWidth(context)这个方法就是获取屏幕的宽度。
 
YCoord() 方法是:根据传入的要显示的参数,把这些值转换为屏幕上Y轴的像素,然后绘制出数据点。转换的跪着就是计算y轴上每一个间距对应的像素的一个比率K,然后用最大值减去传入的参数得到的值乘,这个K,再加上上面空隙的间距,就是返回的值(这写的。。。。我自己都看不懂。。。。。。)反正就是一个数学的比率。

 
反正代码很简单,复习一下。。。。

 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值