AndroidCharts 是一款轻量级的图表显示控件,对比起Android-Charts和AChartEngine来说简单和活泼了很多,适合数据展示不需要太过详细专业的场合,它支持简单且带动画的折线图,柱状图和饼状图。
其中的linechart不支持y坐标显示,我们可以自己修改添加上去,修改后类LineView的代码如下,其中YCOORD_TEXT_LEFT_MARGIN为图标向右的偏移量,用来空出y坐标文字的空间:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
package com.nekocode.xuedao.utils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.NinePatchDrawable; import android.util.AttributeSet; import android.view.View; import java.util.ArrayList; import com.nekocode.xuedao.R; /** * Created by Dacer on 11/4/13. */ public class LineView extends View { private int mViewHeight; //drawBackground private boolean autoSetDataOfGird = true ; private boolean autoSetGridWidth = true ; private int dataOfAGird = 10 ; private int bottomTextHeight = 0 ; private ArrayList<string> bottomTextList; private ArrayList<integer> dataList; private ArrayList<integer> xCoordinateList = new ArrayList<integer>(); private ArrayList<integer> yCoordinateList = new ArrayList<integer>(); private ArrayList<dot> drawDotList = new ArrayList<dot>();; private Paint bottomTextPaint = new Paint(); private Paint ycoordTextPaint = new Paint(); private int bottomTextDescent; //popup private Paint popupTextPaint = new Paint(); private final int bottomTriangleHeight = 12 ; //private Dot selectedDot; private boolean mShowYCoordinate = true ; private int topLineLength = MyUtils.dip2px(getContext(), 12 );; // | | 鈫this //-+-+- private int sideLineLength = MyUtils.dip2px(getContext(), 45 )/ 3 * 2 ; // --+--+--+--+--+--+-- // 鈫this 鈫 private int backgroundGridWidth = MyUtils.dip2px(getContext(), 45 ); //Constants private final int popupTopPadding = MyUtils.dip2px(getContext(), 2 ); private final int popupBottomMargin = MyUtils.dip2px(getContext(), 5 ); private final int bottomTextTopMargin = MyUtils.sp2px(getContext(), 5 ); private final int bottomLineLength = MyUtils.sp2px(getContext(), 22 ); private final int DOT_INNER_CIR_RADIUS = MyUtils.dip2px(getContext(), 2 ); private final int DOT_OUTER_CIR_RADIUS = MyUtils.dip2px(getContext(), 5 ); private final int MIN_TOP_LINE_LENGTH = MyUtils.dip2px(getContext(), 12 ); private final int MIN_VERTICAL_GRID_NUM = 4 ; private final int MIN_HORIZONTAL_GRID_NUM = 1 ; private final int BACKGROUND_LINE_COLOR = Color.parseColor( "#EEEEEE" ); private final int BOTTOM_TEXT_COLOR = Color.parseColor( "#9B9A9B" ); private final int YCOORD_TEXT_LEFT_MARGIN = MyUtils.dip2px(getContext(), 10 ); class YCoordData { private int y; private int data; public int getY() { return y; } public void setY( int y) { this .y = y; } public int getData() { return data; } public void setData( int data) { this .data = data; } } private Runnable animator = new Runnable() { @Override public void run() { boolean needNewFrame = false ; for (Dot dot : drawDotList){ dot.update(); if (!dot.isAtRest()){ needNewFrame = true ; } } if (needNewFrame) { postDelayed( this , 0 ); } invalidate(); } }; public LineView(Context context){ this (context, null ); } public LineView(Context context, AttributeSet attrs){ super (context, attrs); popupTextPaint.setAntiAlias( true ); popupTextPaint.setColor(Color.WHITE); popupTextPaint.setTextSize(MyUtils.sp2px(getContext(), 13 )); popupTextPaint.setStrokeWidth( 5 ); popupTextPaint.setTextAlign(Paint.Align.CENTER); bottomTextPaint.setAntiAlias( true ); bottomTextPaint.setTextSize(MyUtils.sp2px(getContext(), 12 )); bottomTextPaint.setTextAlign(Paint.Align.CENTER); bottomTextPaint.setStyle(Paint.Style.FILL); bottomTextPaint.setColor(BOTTOM_TEXT_COLOR); ycoordTextPaint.setAntiAlias( true ); ycoordTextPaint.setTextSize(MyUtils.sp2px(getContext(), 12 )); ycoordTextPaint.setTextAlign(Paint.Align.LEFT); ycoordTextPaint.setStyle(Paint.Style.FILL); ycoordTextPaint.setColor(BOTTOM_TEXT_COLOR); } /** * dataList will be reset when called is method. * @param bottomTextList The String ArrayList in the bottom. */ public void setBottomTextList(ArrayList<string> bottomTextList){ this .dataList = null ; this .bottomTextList = bottomTextList; Rect r = new Rect(); int longestWidth = 0 ; String longestStr = "" ; bottomTextDescent = 0 ; for (String s:bottomTextList){ bottomTextPaint.getTextBounds(s, 0 ,s.length(),r); if (bottomTextHeight<r.height()){ bottomtextheight= "r.height();" }= "" if (autosetgridwidth&&(longestwidth<r.width())){= "" longestwidth= "r.width();" longeststr= "s;" if (bottomtextdescent<(math.abs(r.bottom))){= "" bottomtextdescent= "Math.abs(r.bottom);" if (autosetgridwidth){= "" if (backgroundgridwidth<longestwidth){= "" backgroundgridwidth= "longestWidth+(int)bottomTextPaint.measureText(longestStr,0,1);" if (sidelinelength<longestwidth= "" 2 ){= "" sidelinelength= "longestWidth/2;" refreshxcoordinatelist(gethorizontalgridnum());= "" **= "" *= "" @param = "" datalist= "" the= "" integer= "" arraylist= "" for = "" showing,= "" datalist.size()= "" must= "" <= "" bottomtextlist.size()= "" public = "" void = "" setdatalist(arraylist<integer= "" > dataList){ this .dataList = dataList; if (dataList.size() > bottomTextList.size()){ throw new RuntimeException( "dacer.LineView error:" + " dataList.size() > bottomTextList.size() !!!" ); } if (autoSetDataOfGird){ int biggestData = 0 ; for (Integer i:dataList){ if (biggestData<i){ biggestdata= "i;" }= "" dataofagird= "1;" while (biggestdata= "" 10 = "" > dataOfAGird){ dataOfAGird *= 10 ; } } refreshAfterDataChanged(); setMinimumWidth( 0 ); // It can help the LineView reset the Width, // I don't know the better way.. postInvalidate(); } public void setShowYCoordinate( boolean showYCoordinate) { mShowYCoordinate = showYCoordinate; } private void refreshAfterDataChanged(){ int verticalGridNum = getVerticalGridlNum(); refreshTopLineLength(verticalGridNum); refreshYCoordinateList(verticalGridNum); refreshDrawDotList(verticalGridNum); } private int getVerticalGridlNum(){ int verticalGridNum = MIN_VERTICAL_GRID_NUM; if (dataList != null && !dataList.isEmpty()){ for (Integer integer:dataList){ if (verticalGridNum<(integer+ 1 )){ verticalGridNum = integer+ 1 ; } } } return verticalGridNum; } private int getHorizontalGridNum(){ int horizontalGridNum = bottomTextList.size()- 1 ; if (horizontalGridNum<min_horizontal_grid_num){ horizontalgridnum= "MIN_HORIZONTAL_GRID_NUM;" }= "" return = "" horizontalgridnum;= "" private = "" void = "" refreshxcoordinatelist( int = "" horizontalgridnum){= "" xcoordinatelist.clear();= "" for ( int = "" i= "0;i<(horizontalGridNum+1);i++){" xcoordinatelist.add(sidelinelength= "" += "" backgroundgridwidth*i);= "" refreshycoordinatelist( int = "" verticalgridnum){= "" ycoordinatelist.clear();= "" ycoordinatelist.add(toplinelength= "" ((mviewheight-toplinelength-bottomtextheight-bottomtexttopmargin-= "" bottomlinelength-bottomtextdescent)*i= "" (verticalgridnum)));= "" refreshdrawdotlist( int = "" if (datalist= "" != "null" &&= "" !datalist.isempty()){= "" int = "" drawdotsize= "drawDotList.isEmpty()?" 0 :drawdotlist.size();= "" x= "xCoordinateList.get(i);" y= "yCoordinateList.get(verticalGridNum" -= "" datalist.get(i));= "" if (i= "" >drawDotSize- 1 ){ drawDotList.add( new Dot(x, 0 , x, y, dataList.get(i))); } else { drawDotList.set(i, drawDotList.get(i).setTargetData(x,y,dataList.get(i))); } } int temp = drawDotList.size() - dataList.size(); for ( int i= 0 ; i<temp; i++){= "" drawdotlist.remove(drawdotlist.size()- 1 );= "" }= "" removecallbacks(animator);= "" post(animator);= "" private = "" void = "" refreshtoplinelength( int = "" verticalgridnum){= "" for = "" prevent= "" popup= "" can't= "" be= "" completely= "" showed= "" when= "" backgroundgridheight= "" is= "" too= "" small.= "" but= "" this = "" code= "" not= "" so= "" good.= "" if ((mviewheight-toplinelength-bottomtextheight-bottomtexttopmargin)= "" (verticalgridnum+ 2 )<getpopupheight()){= "" toplinelength= "getPopupHeight()+DOT_OUTER_CIR_RADIUS+DOT_INNER_CIR_RADIUS+2;" } else {= "" @override = "" protected = "" ondraw(canvas= "" canvas)= "" {= "" drawbackgroundlines(canvas);= "" drawlines(canvas);= "" drawdots(canvas);= "" for (dot= "" dot= "" := "" drawdotlist){= "" drawpopup(canvas,= "" string.valueof(dot.data),= "" dot.getpoint());= "" *= "" if (showpopup= "" &&= "" selecteddot= "" != "null){" string.valueof(selecteddot.data),= "" selecteddot.getpoint());= "" }*= "" **= "" @param = "" canvas= "" the= "" you= "" need= "" to= "" draw= "" on.= "" point= "" consists= "" of= "" x= "" y= "" coordinates= "" from= "" left= "" bottom= "" right= "" top.= "" like= "" 3 = "" 2 = "" 1 = "" 0 = "" 4 = "" 5 = "" drawpopup(canvas= "" canvas,string= "" num,= "" point){= "" boolean = "" singularnum= "(num.length()" == "1);" int = "" sidepadding= "MyUtils.dip2px(getContext(),singularNum?" 8 : 5 );= "" if (mshowycoordinate= "=" true )= "" += "YCOORD_TEXT_LEFT_MARGIN;" rect= "" popuptextrect= "new" rect();= "" popuptextpaint.gettextbounds(num, 0 ,num.length(),popuptextrect);= "" r= "new" rect(x-popuptextrect.width()= "" 2 -sidepadding,= "" -= "" popuptextrect.height()-bottomtriangleheight-popuptoppadding* 2 -popupbottommargin,= "" popuptextrect.width()= "" 2 +sidepadding,= "" y+popuptoppadding-popupbottommargin);= "" bitmap= "" bmp= "BitmapFactory.decodeResource(getResources()," r.drawable.popup_red);= "" byte = "" chunk[]= "bmp.getNinePatchChunk();" ninepatchdrawable= "" ninepatchdrawable(bmp,= "" chunk,= "" new = "" rect(),= "" null );= "" popup.setbounds(r);= "" popup.draw(canvas);= "" canvas.drawtext(num,= "" x,= "" y-bottomtriangleheight-popupbottommargin,= "" popuptextpaint);= "" getpopupheight(){= "" popuptextpaint.gettextbounds( "9" , 0 , 1 ,popuptextrect);= "" rect(-popuptextrect.width()= "" 2 ,= "" +popuptoppadding-popupbottommargin);= "" return = "" r.height();= "" drawdots(canvas= "" canvas){= "" paint= "" bigcirpaint= "new" paint();= "" bigcirpaint.setantialias( true );= "" bigcirpaint.setcolor(color.parsecolor( "#ff0033" ));= "" smallcirpaint= "new" paint(bigcirpaint);= "" smallcirpaint.setcolor(color.parsecolor( "#ffffff" ));= "" if (drawdotlist!= "null" !drawdotlist.isempty()){= "" canvas.drawcircle(x,dot.y,dot_outer_cir_radius,bigcirpaint);= "" canvas.drawcircle(x,dot.y,dot_inner_cir_radius,smallcirpaint);= "" drawlines(canvas= "" linepaint= "new" linepaint.setantialias( true );= "" linepaint.setcolor(color.parsecolor( "#ff0033" ));= "" linepaint.setstrokewidth(myutils.dip2px(getcontext(),= "" 2 ));= "" for ( int = "" i= "0;" i<drawdotlist.size()- 1 ;= "" x1= "drawDotList.get(i).x;" x2= "drawDotList.get(i+1).x;" canvas.drawline(x1,= "" drawdotlist.get(i).y,= "" x2,= "" drawdotlist.get(i+ 1 ).y,= "" linepaint);= "" drawbackgroundlines(canvas= "" paint.setstyle(paint.style.stroke);= "" paint.setstrokewidth(myutils.dip2px(getcontext(),1f));= "" paint.setcolor(background_line_color);= "" vertical= "" lines= "" canvas.drawline(x,= "" 0 ,= "" mviewheight= "" bottomtexttopmargin= "" bottomtextheight-bottomtextdescent,= "" paint);= "" if ((ycoordinatelist.size()- 1 -i)%dataofagird= "=" 0 ){= "" canvas.drawline( 0 ,= "" y,= "" getwidth(),= "" canvas.drawtext(string.valueof(ycoordinatelist.size()-i- 1 ),= "" ycoordtextpaint);= "" text= "" if (bottomtextlist= "" canvas.drawtext(bottomtextlist.get(i),= "" mviewheight-bottomtextdescent,= "" bottomtextpaint);= "" onmeasure( int = "" widthmeasurespec,= "" heightmeasurespec)= "" mviewwidth= "measureWidth(widthMeasureSpec);" refreshafterdatachanged();= "" setmeasureddimension(mviewwidth,mviewheight);= "" measurewidth( int = "" measurespec){= "" horizontalgridnum= "getHorizontalGridNum();" preferred= "backgroundGridWidth*horizontalGridNum+sideLineLength*2;" getmeasurement(measurespec,= "" preferred);= "" measureheight( int = "" getmeasurement( int = "" measurespec,= "" preferred){= "" specsize= "MeasureSpec.getSize(measureSpec);" measurement;= "" switch (measurespec.getmode(measurespec)){= "" case = "" measurespec.exactly:= "" measurement= "specSize;" break ;= "" measurespec.at_most:= "" specsize);= "" default := "" public = "" ontouchevent(motionevent= "" event)= "" point();= "" point.x= "(int)" event.getx();= "" point.y= "(int)" event.gety();= "" region= "" region();= "" width= "backgroundGridWidth/2;" if (drawdotlist= "" ||= "" r.set(dot.x-width,dot.y-width,dot.x+width,dot.y+width);= "" if = "" (r.contains(point.x,point.y)= "" event.getaction()= "=" motionevent.action_down){= "" } else = "" (event.getaction()= "=" motionevent.action_up){= "" (r.contains(point.x,point.y)){= "" showpopup= "true;" motionevent.action_down= "" postinvalidate();= "" true ;= "" updateself( int = "" origin,= "" target,= "" velocity){= "" (origin= "" <= "" target)= "" origin= "" else = "" > target){ origin-= velocity; } if (Math.abs(target-origin)<velocity){ origin= "target;" }= "" return = "" origin;= "" class = "" dot{= "" int = "" x;= "" y;= "" data;= "" targetx;= "" targety;= "" velocity= "MyUtils.dip2px(getContext(),20);" dot( int = "" x, int = "" y, int = "" targetx, int = "" targety,integer= "" data){= "" this .x= "x;" this .y= "y;" settargetdata(targetx,= "" targety,data);= "" point= "" getpoint(){= "" new = "" point(x,y);= "" dot= "" settargetdata( int = "" this .targetx= "targetX;" this .targety= "targetY;" this .data= "data;" this ;= "" boolean = "" isatrest(){= "" (x= "=targetX)&&(y==targetY);" void = "" update(){= "" x= "updateSelf(x," targetx,= "" velocity);= "" y= "updateSelf(y," targety,= "" <= "" pre= "" ><br> 修改后我们可以通过增加的setShowYCoordinate方法设置是否显示y坐标文字。<p></p> <p><img src= "http://www.2cto.com/uploadfile/Collfiles/20140116/2014011609191312.jpg" alt= "" style= "height: 560px; 350px;" ><br> </p> </velocity){></temp;></min_horizontal_grid_num){></i) |