1. Introduction
Weekend in the network, saw a study plan report chart, detailed records of their own week of study, every day is 0 lessons Ah! Just learning the Android custom view, so think of yourself to write a, here first give a picture of the Nets, and their own.
Yissan's blog, without permission is strictly prohibited reprint Http://blog.csdn.net/yissan
2. Realization Analysis
We want to implement such a line chart, the necessary information is mainly the following several
Look at the vertical axis, the vertical axis needs the maximum value of information, but also useful to determine the unit each spacing represents, such as the maximum value is 100, we also have a value divided into several data.
Next look at the horizontal axis, because the horizontal axis of information is generally text, not like the number can be obtained by accumulating, so directly save a string array variable.
Then it's the polyline, and the polyline only needs to determine the y-coordinate of the vertical axis of each axis, and then it's OK to connect it, just to get the specific coordinates of y based on the spacing of the units on the left and the values of each unit.
Then you need to sum up:
1, longitudinal axis maximum value
2, longitudinal axis Division number
3. The value of each small unit in the longitudinal axis is calculated by the maximum/split quantity
4. Arrays for horizontal display
5, horizontal, longitudinal axis spacing
6, specific array (used to draw the polyline)
With the information above you can go to draw, the following to start the specific custom view steps to explain
3. Concrete Realization
In the previous article, I wrote an article that introduced a custom step--Learning Android custom Control 1 together, and we followed this step to explain.
(1) CREATE view
Primarily determines whether the inherited view is a specific view, defines and gets properties, and adds a set property method.
Defining properties
<?xml version= "1.0" encoding= "Utf-8"?><resources> <declare-styleable name="Statisticsview"> <attr name="MaxValue" format="integer"></attr> <attr name="Dividercount" format="integer"> </attr> <attr name="title" format="integer"></attr> <attr name="LineColor" format="Color"></attr> <attr name="TextColor" format="Color"></attr> <attr name="Pathcolor" format="Color"></attr> </declare-styleable></Resources>
Getting properties in a construction method
Public class statisticsview extends View { //Draw horizontal longitudinal axis PrivatePaint Mborderpaint;//Draw the center of the coordinate point PrivatePaint Circlepaint;//Draw a line chart PrivatePaint Mpathpaint;PrivatePath MPath;//longitudinal axis maximum value Private intMaxValue = -;//longitudinal axis split quantity Private intDividercount =Ten;PrivateString title ="7th Learning Situation (Unit section)";//Vertical axis per unit value Private intPervalue = Maxvalue/dividercount;//Bottom display string PrivateString[] bottomstr = {};//Specific values Private float[] values = {};//Bottom horizontal Unit spacing Private floatBottomgap;//Left longitudinal axis spacing Private floatLeftgap;PrivateTextpaint Textpaint; Public void setvalues(float[] values) { This. values = values; Invalidate (); } Public void Setbottomstr(string[] bottomstr) { This. bottomstr = Bottomstr; Requestlayout (); } Public Statisticsview(Context context) {Super(context); } Public Statisticsview(context context, AttributeSet attrs) { This(Context, Attrs,0); } Public Statisticsview(context context, AttributeSet attrs,intDEFSTYLEATTR) {Super(Context, attrs, defstyleattr); TypedArray array = context.obtainstyledattributes (Attrs, R.styleable.statisticsview); MaxValue =array.getint (R.styleable.statisticsview_maxvalue, -); Dividercount = Array.getint (R.styleable.statisticsview_dividercount,Ten); title = Array.getstring (R.styleable.statisticsview_title);intLineColor = Array.getcolor (R.styleable.statisticsview_linecolor,color.black);intTextColor =array.getcolor (R.styleable.statisticsview_textcolor,color.black); Mborderpaint =NewPaint (); Circlepaint =NewPaint (); Mpathpaint =NewPaint (); Mborderpaint.setantialias (true); Mborderpaint.setcolor (LineColor); Mborderpaint.setstrokewidth (1); Mborderpaint.setstyle (Paint.Style.STROKE); Mpathpaint.setantialias (true); Mpathpaint.setstyle (Paint.Style.STROKE); Mpathpaint.setstrokewidth (3); Textpaint =NewTextpaint (); Textpaint.setcolor (TextColor); Textpaint.settextsize (dip2px (GetContext (), A)); MPath =NewPath (); Circlepaint.setstyle (Paint.Style.FILL); Circlepaint.setantialias (true); Array.recycle (); }}
The above code simply gets the properties and initializes some information. At the same time, the method of setting values is provided externally.
(2) handling the layout of the view
The first consideration in handling layouts is to override the Onmeasure method as needed. Here, for the sake of simplicity, direct wrap_content is equal to the direct width and height of the case. Of course you can also have a property representing the width of each pitch, and then calculate the width height under wrap_content.
@Override protected void onmeasure(intWidthmeasurespec,intHEIGHTMEASURESPEC) {intWidthmode = Measurespec.getmode (Widthmeasurespec);intWidthsize = Measurespec.getsize (Widthmeasurespec);intHeightmode = Measurespec.getmode (Heightmeasurespec);intHeightsize = Measurespec.getsize (Heightmeasurespec);if(widthmode==measurespec.exactly&&heightmode==measurespec.exactly) {setmeasureddimension (widthsize,heightsize); }Else if(widthmeasurespec==measurespec.exactly) {setmeasureddimension (widthsize,widthsize); }Else if(heightmeasurespec==measurespec.exactly) {setmeasureddimension (heightsize,heightsize); } }
Since it is necessary to determine the unit spacing of the horizontal axis at draw, we need to get it, generally we get the value can be obtained in the Onsizechange method, but because the gap at the bottom of our base needs to be displayed according to several to determine. But it only started when bottomstr[] has a length of 0, and then the set method for the BOTTOMSTR setting does not call Onsizechange again. Bottomgap will be the first value, so the effect will be problematic, so it is taken in the OnLayout method.
@Override protectedvoidonLayout(booleanintintintint bottom) { bottomGap = getWidth()/(bottomStr.length+1); leftGap = getHeight()/(dividerCount+2); super.onLayout(changed, left, top, right, bottom); }
(3), Draw view (draw)
Next, you can implement OnDraw () to draw the view
@Override protected void OnDraw(Canvas canvas) {Super. OnDraw (canvas);if(bottomstr==NULL|| bottomstr.length==0){return; }//Draw the left lineCanvas.drawline (Bottomgap,getheight ()-leftgap,bottomgap,leftgap,mborderpaint);floatFontheight = (Textpaint.getfontmetrics (). Descent-textpaint.getfontmetrics (). Ascent);//Draw down the edgeCanvas.drawline (Bottomgap,getheight ()-leftgap,getwidth ()-bottomgap,getheight ()-leftgap,mborderpaint); for(inti =1; i<=bottomstr.length;i++) {canvas.drawcircle (I*bottomgap,getheight ()-leftgap,6, Circlepaint); Canvas.drawtext (bottomstr[i-1],i*bottomgap-(Textpaint.measuretext (bottomstr[i-1])/2), GetHeight ()-leftgap/2+fontheight/2, Textpaint); } canvas.drawtext (title,bottomgap,leftgap/2, Textpaint); for(inti =1; i<=dividercount+1; i++) {//Draw the left wordCanvas.drawtext (pervalue* (i-1)+"", bottomgap/2-(Textpaint.measuretext (pervalue* (i-1)+"")/2), (((dividercount+2-i)) *leftgap+fontheight/2, Textpaint);//Draw horizontal LineCanvas.drawline (Bottomgap,getheight ()-((i) *leftgap), getwidth ()-bottomgap,getheight ()-((i) *leftgap), Mborderpaint); }/** * Plot trajectory * Y coordinate point according to Y/LEFTGAP = values[i]/pervalue calculation * */ for(inti =0; i<values.length;i++) {if(i==0) {Mpath.moveto (Bottomgap, dividercount+1) *leftgap-(Values[i]*leftgap/pervalue)); }Else{Mpath.lineto (i+1) *bottomgap, (dividercount+1) *leftgap-(Values[i]*leftgap/pervalue)); }/** * Draw Trajectory dots * /Canvas.drawcircle ((i+1) *bottomgap, (dividercount+1) *leftgap-(Values[i]*leftgap/pervalue),6, Circlepaint); } canvas.drawpath (Mpath,mpathpaint); } Public Static int dip2px(Context context,floatDpvalue) {Final floatScale = Context.getresources (). Getdisplaymetrics (). density;return(int) (Dpvalue * scale +0.5f); }
The code is annotated, mostly with calculations, Drawline,drawpath,drawtext, and some knowledge of the text width.
Yissan's blog, without permission is strictly prohibited reprint Http://blog.csdn.net/yissan
4. Use
Declare the view, then get the view in the activity and call the Setbottomstr and Setvalues methods
<com .qiangyu .test . Statisticsview .view android:id= "@+id/statisticsview" android:layout_width = "match_parent" android:layout_height= "300DP" App:viewtitle=/>
publicvoid invalidate(View view) { this.view.setBottomStr(new String[]{"星期一","星期二","星期三","星期四","星期五","星期六","星期天"}); this.view.setValues(newfloat[]{10f,90f,33f,66f,42f,99f,0f}); }
Another one.
5. Summary
Custom view is more practice, see a favorite effect, do not want to be able to draw one of their own, a long time, I believe we can easily write a good custom view
Because the work is a little busy recently, so many places are imperfect. Here to share, I hope you like.
Android Custom view4--Chart view