android之自定义View和ViewGroup(六)(代码篇,实现简单的走势图,柱状图同理)
来源:互联网 发布:怎么看淘宝销售排名 编辑:程序博客网 时间:2024/05/22 06:50
项目需要走势图,什么柱状图、走势图,网上都有一堆现成的框架,但是我项目中只需要走势图,我用第三方框架简直是累赘,毕竟占大小,而且走势图也简单,所以就自己写了,好久没写博客了,就记下吧,供大家参考下,其实很简单,大佬勿喷。先不废话,看效果图吧:
记录了七天的走势,原点的x坐标不是0,因为我们不是用来做坐标轴,而是记录数据,原点的坐标根据实际需求情况而定的。
好了,废话说完了,开始动手吧,动手之前我们得先想想怎么实现,思路是怎样的。
首先,我们需要知道我们需要画什么。
1.我们需要画x,y轴;
2.我们需要画x,y轴的刻度和刻度值;
3.我们需要画y轴上的每个刻度的横线;
4.我们需要画数据的点;
5.数据的点需要连线;
大致就是这些,还有些文字的大小啊,颜色啊等等,都可以自己设置;
然后,我们需要知道怎么画。
大家都知道在视图坐标系中,一个view,原点是它的左上角,所以我们需要实际的原点,真实的原点,即走势图中x,y轴的交接点。所以我们得先确定实际原点,假设实际原点的坐标是(xo,yo),averageX代表x轴每个刻度间的距离,那图片中x轴的11.2所在的坐标就是相对于原点的(averageX,0),所以实际坐标就是(xo+averageX,yo+0)。那么y轴的1000所在的坐标就是相对于原点的(0,-averageY),所以实际坐标是(0+xo,-averageY+yo)注意,android中,x轴向右为正,y轴向下为正,所以1000所在的坐标是负的。哎,语文没学好,可能表达有点不清楚?总之呢,就是为了确定每个点的算法才这样计算的。
首先,我们自定义View继承自View,然后相关属性:
private Context context; //x,y轴的画笔,刻度文字的画笔,数据点的画笔,数据连线的画笔,y轴刻度横线的画笔,数据点文字的画笔 private Paint xyPaint, textPaint, pointPaint, pointslinePaint, yLinePaint, pointTextPaint; private int padding; //内部距离,设置个默认的padding值 private int width, height; //控件实际高度和宽度 private float xSize, ySize;//x和y轴的长度(因为控件留了内部距离,不然x,y轴就贴着控件边缘导致看不清,有内部距离,所以长度和控件的宽高不一样了) private int defaultWidth; //默认宽度 private int defaultHeight; //默认高度 private int xOrigin, yOrigin; //相对原点的坐标 private String[] xPoints; //x轴显示的坐标 private String[] yPoints; //y轴显示的坐标 private List<Float> xPointList, yPointList; //数据点的x坐标集合,y坐标集合;
然后初始化画笔,默认高宽等等:
private void init() { xPointList = new ArrayList<>(); yPointList = new ArrayList<>(); defaultWidth = (DisplayUtils.width > 480 ? 480 : DisplayUtils.width); defaultHeight = 320; padding = DisplayUtils.dip2px(context, 35); xyPaint = new Paint(); xyPaint.setStyle(Paint.Style.FILL); xyPaint.setAntiAlias(true); textPaint = new Paint(); textPaint.setStyle(Paint.Style.FILL); textPaint.setAntiAlias(true); textPaint.setTextSize(DisplayUtils.dip2px(context, 10)); pointPaint = new Paint(); pointPaint.setStyle(Paint.Style.FILL); pointPaint.setAntiAlias(true); pointslinePaint = new Paint(); pointslinePaint.setStyle(Paint.Style.FILL); pointslinePaint.setAntiAlias(true); pointslinePaint.setStrokeWidth(6); yLinePaint = new Paint(); yLinePaint.setStyle(Paint.Style.FILL); yLinePaint.setAntiAlias(true); pointTextPaint = new Paint(); pointTextPaint.setStyle(Paint.Style.FILL); pointTextPaint.setAntiAlias(true); pointTextPaint.setTextSize(DisplayUtils.dip2px(context, 6)); }
为了简单,我就不再attr中设置属性了,直接在代码里面设置颜色值之类的,大家知道思路就好。
设置一个public方法供外部调用来设置数据点的坐标,我们用Map来保存坐标:
public void setData(String[] xPoints, String[] yPoints, Map<Float, Float> showPointsMap) { this.xPoints = xPoints; this.yPoints = yPoints; for (float x : showPointsMap.keySet()) { xPointList.add(x); yPointList.add(showPointsMap.get(x)); } }
设置一个public方法供外部调用,来设置画笔的颜色:
//x,y轴和刻度文字的画笔,数据点的画笔,数据连线的画笔,y轴刻度横线的画笔,数据点文字的画笔 public void setColor(int xyColor, int pointColor, int lineColor, int yLineColor, int pointTextColor) { xyPaint.setColor(xyColor); textPaint.setColor(xyColor); pointPaint.setColor(pointColor); pointslinePaint.setColor(lineColor); yLinePaint.setColor(yLineColor); pointTextPaint.setColor(pointTextColor); }
然后接下来开始自定义的方法,先onMeasure()方法确定大小,如果测量模式不是EXACYLY,那么就使用默认的高宽值:
if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { width = defaultWidth; } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { height = defaultHeight; } ySize = height - padding - 60; //y轴总长度,y轴的paddingTop我只留60px,paddingButtom留padding大小,可以自己定义 xSize = width - padding * 2; //x轴总长度,x方向的左右padding都设置为padding大小 xOrigin = padding; //实际原点的x坐标 yOrigin = height - padding; //实际原点的y坐标 setMeasuredDimension(width, height);
然后重要的onDraw()方法:
float averageHeight = ySize / 5; //y轴每个刻度之间的长度,设置6个刻度 float averageWidth = xSize / 6; //x轴每个刻度之间的长度,设置7个刻度 float averagePx = ySize / 5000; canvas.drawLine(xOrigin, yOrigin, xOrigin + xSize + 15, yOrigin, xyPaint); //画x轴,多画了15px让x轴右边可以出来,不然顶部正好是最后一个刻度线 canvas.drawLine(xOrigin, yOrigin, xOrigin, yOrigin - ySize - 15, xyPaint); //画y轴,多画了15px让y轴上边可以出来,不然顶部正好是最后一个刻度线 for (int i = 0; i < yPoints.length; i++) { //画y轴上的刻度,y轴刻度的横线,y轴刻度文字 canvas.drawLine(xOrigin, yOrigin - averageHeight * (i + 1), xOrigin - 15, yOrigin - averageHeight * (i + 1), xyPaint); canvas.drawLine(xOrigin, yOrigin - averageHeight * (i + 1), xOrigin + xSize + 15, yOrigin - averageHeight * (i + 1), yLinePaint); canvas.drawText(yPoints[i], 10, yOrigin - averageHeight * (i + 1), textPaint); } for (int i = 0; i < xPoints.length; i++) { //画x轴上的刻度和文字 canvas.drawLine(xOrigin + averageWidth * i, yOrigin, xOrigin + averageWidth * i, yOrigin + 15, xyPaint); canvas.drawText(xPoints[i], xOrigin + averageWidth * (i), height - 30, textPaint); } for (int i = 0; i < xPointList.size(); i++) { //画走势连线 if (i < xPointList.size() - 1) { canvas.drawLine(xOrigin + averageWidth * (i), yOrigin - averagePx * yPointList.get(i), xOrigin + averageWidth * (i + 1), yOrigin - averagePx * yPointList.get(i + 1), pointslinePaint); } } for (int i = 0; i < xPointList.size(); i++) { //画数据点,先画线是为了让点可以盖住线 canvas.drawCircle(xOrigin + averageWidth * (i), yOrigin - averagePx * yPointList.get(i), 10, pointPaint); //数据点 canvas.drawText(yPointList.get(i) + "", xOrigin + averageWidth * (i) + 20, yOrigin - averagePx * yPointList.get(i), pointTextPaint); //数据文字 }
思路其实很简单,也没任何难点,就是画点,画线,画刻度。需要说的都在代码中写明了,就不啰嗦了,主要是知道思路,剩下的就简单了。
其实还有很多可以优化的地方,比如自定义属性颜色值,字体大小,线条粗细,数据点的大小,刻度值的位置等等,都可以自定义,这些比较简单我就不啰嗦了,有兴趣的朋友可以去试试。对于柱状图,其实一样的原理。
- android之自定义View和ViewGroup(六)(代码篇,实现简单的走势图,柱状图同理)
- android之自定义view和ViewGroup(三)(代码篇,实现条形进度条)
- android之自定义View和ViewGroup(四)(代码篇,实现圆形进度条)
- android之自定义View和ViewGroup(五)(代码篇,实现类似竖着的ViewPager引导页,竖向引导页)
- android之自定义View和ViewGroup(一)(此篇不讲述代码,只讲述原理和结构,带你走进自定义的世界)
- android之自定义View和ViewGroup(二)(此篇不讲述代码,只讲述原理和结构,带你走进自定义的世界)
- android 自定义 view 之ViewGroup(四)
- Android自定义View实现简单的折线图、柱状图
- Android开发之自定义View专题(四):自定义ViewGroup
- 自定义view走势图(二、加入动画和触摸事件)
- Android 自定义View 和 ViewGroup
- Android 自定义View和ViewGroup
- Android自定义View和ViewGroup
- 自定义view画走势图(一)
- 自定义view走势图(三、贝塞尔曲线)
- 自定义View绘制心得(自定义view和自定义viewGroup)
- 【Android】自定义View -- 条形图(柱状图)
- Android自定义View(三)柱状图
- TP框架学习笔记第一天
- 做一个串行执行的存储过程
- Android ScrollView 中放入 ImageView 导致的出现上下白边的问题?
- HTML iframe框架
- 【IMWeb训练营作业】 todoList
- android之自定义View和ViewGroup(六)(代码篇,实现简单的走势图,柱状图同理)
- Android WebView显示广告
- Hive的操作
- 2017中国虚拟现实教育创新大会暨第二届高校虚拟现实学科建设研讨会
- MySQL修改表结构
- ZOJ2405-Specialized Four-Digit Numbers
- 微信公众号验证token+关注回复+关键字回复+单图文回复
- Spring学习:bean的初始化和销毁及Aware(xml)
- 赛码网-在线编程:翻转数组