概括
最近做一个项目,有个需要折线图的需求,刚开始自己很犯懒,就想着随便从网上找个用就用,后来发现网上的介绍和案例,都是各有千秋,对我来说用他们都不是那么的完美,
比如一线介绍简单的画法,确实介绍的太简单了,如果改造他们的,太麻烦,真不如我自己重写,也有比较强大的三方库,比如HelloCharts和MPAndroidChart等,他们不但能满足画折线基本需要,而且还能实现了负责的动画功能,不过他们也有自己的短处,比如HelloCharts的y轴刻度不能自定义,MPAndroidChart折线显示数据的显示不好自定义,可能时间有限,我也没深入研究他们的源码,想来想去还是自己写个吧,毕竟他们体积还是有点大,我只是需要一个简单折线图,
原理
其实画折线图的原理很简单,就是在ondraw里利用画布Cavans根据你的需要,确定好X轴和Y轴,然后画出来,在这个过程中第一点就是要确认你的原点坐标,第二点就是你的布局总大小和你的X的长度和Y轴的高度,第三部就是X轴和Y轴分几等分,然后根据这几点画出你需要的折线,其中细节算法大家可以根据自己的项目需要来定义,好吧闲话少说咱们直接上代码吧。
代码:
canvas.drawLine(mXor, mYor, mXor, mYor - mHeight, mPaint == null ? mDefaultPaint : mPaint);//y轴 //画y轴上的刻度 List<Float> yLineValue = new ArrayList<>(); yLineValue.add(4f); yLineValue.add(4 + mRato); yLineValue.add(4 + mRato * 2); yLineValue.add(4 + mRato * 3); yLineValue.add(4 + mRato * 4); yLineValue.add(4 + mRato * 5); for (int i = 0; i < mLineNum + 1; i++) { //画y轴刻度 canvas.drawText("" + yLineValue.get(i), mXor - dp2px(15), mYor - mYSpace * i, mTextPaint == null ? mDefaultTextPaint : mTextPaint); if ((i != 0) && mIsYGridLine) { canvas.drawLine(mXor - 5, mYor - mYSpace * i, mXor + mWidth, mYor - mYSpace * i, mPaint == null ? mDefaultPaint : mPaint);//垂直Y轴的线非x轴 } } canvas.drawLine(mXor, mYor, mXor + mWidth, mYor, mPaint == null ? mDefaultPaint : mPaint);//x轴 //画x轴上的刻度线 for (int j = 1; j < 7; j++) { canvas.drawLine(mXor + mXSpace * j, mYor, mXor + mXSpace * j, mYor + 5, mPaint == null ? mDefaultPaint : mPaint); if (mIsXGridLine) { canvas.drawLine(mXor + mXSpace * j, mYor, mXor + mXSpace * j, mYor - mHeight, mPaint == null ? mDefaultPaint : mPaint); //垂直x轴的线,非Y轴 } } //画x轴刻度线上的值 List<String> xLineValues = getDates(); for (int j = 0; j < xLineValues.size(); j++) { canvas.drawText(xLineValues.get(j), mXor + mXSpace * j - mTextSize * 1.5f, mYor + dp2px(15), mTextPaint == null ? mDefaultTextPaint : mTextPaint); } //画曲线 List<Float> xyLineValue = new ArrayList<>(); xyLineValue.add(4.53f); xyLineValue.add(4.50f); xyLineValue.add(4.55f); xyLineValue.add(4.57f); xyLineValue.add(4.53f); xyLineValue.add(4.60f); xyLineValue.add(4.62f); if (mIsFill) { Path linePath = new Path(); linePath.moveTo(mXor + 4, mYor - 2); for (int i = 0; i < xyLineValue.size(); i++) { linePath.lineTo(mXor + mXSpace * i, mYor - createLineValue(xyLineValue.get(i))); } linePath.lineTo(mXor + mWidth - 4, mYor - 2); canvas.drawPath(linePath, mFillPaint == null ? mDefaultFillPaint : mFillPaint); if (mValuePaint == null) { mDefaultValuePaint.setStrokeWidth(6); } else { mValuePaint.setStrokeWidth(6); } } Path linePath1 = new Path(); for (int i = 0; i < xyLineValue.size(); i++) { if (i == 0) { linePath1.moveTo(mXor, mYor - createLineValue(xyLineValue.get(i))); } else { linePath1.lineTo(mXor + mXSpace * i, mYor - createLineValue(xyLineValue.get(i))); } } canvas.drawPath(linePath1, mValuePaint == null ? mDefaultValuePaint : mValuePaint); for (int i = 0; i < xyLineValue.size(); i++) { //画曲线上的点 if (mIsShowValues) { canvas.drawText("" + xyLineValue.get(i), mXor + mXSpace * i - mTextSize * 1.5f, mYor - createLineValue(xyLineValue.get(i)) - dp2px(8), mTextPaint == null ? mDefaultTextPaint : mTextPaint); float xCenter = mXor + mXSpace * i; float yCenter = mYor - createLineValue(xyLineValue.get(i)); RectF rectF1 = new RectF(xCenter - dp2px(2), yCenter - dp2px(2), xCenter + dp2px(2), yCenter + dp2px(2)); switch (mPointType) { case HOLLOW_CIRCLE: canvas.drawArc(rectF1, 0, 360, false, mPointPaint == null ? mDefaultPointPaint : mPointPaint); break; case SLIDE_CIRCLE: mDefaultPointPaint.reset(); mDefaultPointPaint.setColor(Color.RED); mDefaultPointPaint.setStrokeWidth(2f); mDefaultPointPaint.setStyle(Paint.Style.FILL); canvas.drawArc(rectF1, 0, 360, true, mPointPaint == null ? mDefaultPointPaint : mPointPaint); break; case HOLLOW_SQUARE: canvas.drawRect(rectF1, mPointPaint == null ? mDefaultPointPaint : mPointPaint); break; case SLIDE_SQUARE: mDefaultPointPaint.reset(); mDefaultPointPaint.setColor(Color.RED); mDefaultPointPaint.setStrokeWidth(2f); mDefaultPointPaint.setStyle(Paint.Style.FILL); canvas.drawRect(rectF1, mPointPaint == null ? mDefaultPointPaint : mPointPaint); break; default: canvas.drawArc(rectF1, 0, 360, false, mPointPaint == null ? mDefaultPointPaint : mPointPaint); break; } } }上面是画折线的核心代码
源码已经上传到github:https://github.com/XinRan5312/QXSimpleLineChart