Android Developer's Custom view feature (ii): Custom pie chart

Source: Internet
Author: User
Tags asin

In the chart, commonly used icons are line chart, column chart and pie chart, last week, bloggers have already shared the column chart. In the blogger's project actually used a pie chart, but no use to the line chart. Actually learned one, and then to write the other, should all know how to write, the principle is to draw their own graphics, and then get touch position to determine the click event. Well, nonsense not much to say directly on today's pie chart


This is also the Bo Master and slave project Inside Out, this time the code comment will be more detailed than the last column chart, more convenient for interested friends to study together. The picture of the circle pointing to the arrow is not part of the pie chart, is in the layout file in order to beautify the other added, interested friends can download the complete project down research study.

: http://download.csdn.net/detail/victorfreedom/8322639

Originally wanted to upload to GitHub, but the network does not give force, a few days to upload it.


The code section directly stickers the custom pie section, supports XML file write constructs, and supports the new method constructs.

Package Com.freedom.piegraph;import Android.annotation.suppresslint;import Android.content.context;import Android.content.res.typedarray;import Android.graphics.canvas;import Android.graphics.color;import Android.graphics.paint;import Android.graphics.rectf;import Android.os.handler;import Android.util.AttributeSet; Import Android.view.motionevent;import android.view.view;/** * @ClassName: Piegraphview * @author victor_freedom ([ Email protected]) * @createddate January 3, 2015 PM 4:30:10 * @Description: Custom pie chart */@SuppressLint ({"Drawallocation"}) public class Piegraphview extends View implements Runnable {//animation speed private float movespeed = 3.0f;//total value private double tot al;//the value of each pie block private double[] itemvaluestemp;//the value corresponding to each pie block private double[] itemsvalues;//the color of each pie private string[] itemcolors;//the angle of each pie block private float[] itemsangle;//The starting angle of the pie block private float[] itemsstartangle;//the proportion of each pie private float[] itemspercent;//rotation starting angle private float Rotatestartang = 0.0f;//rotation end angle private float Rotateendang = 0.0f;//The private Boolean isclockwise;//is rotating private Boolean isrotating;//whether to turn on animation private Boolean isanimenabled = true;// The color of the edge ring private String loopstrokecolor;//the width of the edge ring private float strokewidth = 0.0f;//pie radius, excluding ring private float radius;//current I The position of the TEM is private int itempostion = -1;//dock position private int stopposition = 0;//Dock position public static final int to_right = 0;public static final int to_bottom = 1;public static final int to_left = 2;public static final int to_top = 3;//color value Private final String[] default_items_colors = {"#FF0000", "#FFFF01", "#FF9933", "#9967CC", "#00CCCC", "#00CC33", "#0066CC", "#FF6799", "#99FF01", "#FF67FF", "#4876FF", "#FF00FF", "#FF83FA", "#0000FF", "#363636", "#FFDAB9", "#90EE90", "#8B008B", "#00BFFF", "#FFFF00", "#00FF00", "#006400", "#00FFFF", "#00FFFF", "#668B8B", "#000080", "#008B8B"};//message receiver private Handler Piegraphhandler = new Handler ();//Listener Collection Private Onpiegraphitemselectedlistener itemselectedlistener;public Piegraphview (context context, string[] Itemcolors,doublE[] itemsizes, float total, int radius, int strokewidth,string strokecolor, int stopposition, int separatedistence) {Super (context); this.stopposition = Stopposition;if ((itemsizes! = null) && (itemsizes.length > 0)) {itemvaluestemp = Itemsizes;this.total = total;//Resets the total value resettotal ();//Resets the values of each module refreshitemsangs ();} if (RADIUS < 0)//default radius set to 100this.radius = 100.0f;else {This.radius = radius;} The default ring width is set to 2if (Strokewidth < 0) Strokewidth = 2;else {this.strokewidth = strokewidth;} Loopstrokecolor = strokecolor;if (itemcolors = = null) {//If no color is set, the default color value is used Setdefaultcolor ();} else if ( Itemcolors.length < itemsizes.length) {this.itemcolors = itemcolors;//if the set color value is not the same as the set size, you need to fill in the default color value collection to complement the color, This is generally not the case. Setdifferentcolor ();} else {this.itemcolors = itemcolors;} Invalidate ();} Public Piegraphview (context context, AttributeSet Attrs) {Super (context, attrs); loopstrokecolor = "#000000";// Put our custom attributes in the Attrs property set Typedarray a = Context.obtainstyledattributes (Attrs,r.styleable.piegrAphview); radius = screenutil.dip2px (GetContext (), A.getfloat (R.styleable.piegraphview_radius,)); strokeWidth = SCREENUTIL.DIP2PX (GetContext (), A.getfloat (R.styleable.piegraphview_strokewidth, 2)); movespeed = A.getFloat ( R.styleable.piegraphview_movespeed, 5); if (Movespeed < 1F) {movespeed = 1F;} if (Movespeed > 5.0F) {movespeed = 5.0F;} Invalidate (); A.recycle ();} /** * @Title: Setraduis * @Description: Set RADIUS * @param radius * @throws */public void Setraduis (float radius) {if (radius Lt 0) This.radius = 100.0f;else {This.radius = radius;} Invalidate ();} public float Getraduis () {return radius;} /** * @Title: Setstrokewidth * @Description: Set ring Width * @param strokewidth * @throws */public void setstrokewidth (int stroke Width) {if (Strokewidth < 0) Strokewidth = 2;else {this.strokewidth = strokewidth;} Invalidate ();} public float Getstrokewidth () {return strokewidth;} /** * @Title: Setstrokecolor * @Description: Set the ring color * @param strokecolor * @throws */public void Setstrokecolor (String str OkecoLOR) {Loopstrokecolor = Strokecolor;invalidate ();} Public String Getstrokecolor () {return loopstrokecolor;} /** * @Title: Setitemcolors * @Description: Set the color of the pie block * @param colors * @throws */public void setitemcolors (string[] Colors {if (itemsvalues! = null) && (itemsvalues.length > 0)) {//If the incoming value is not NULL, use the default color if (colors = = null) {Setdefaul TColor ();} else if (Colors.length < itemsvalues.length) {//If the incoming color is not enough, fill itemcolors = Colors;setdifferentcolor () from the default color;} else { itemcolors = colors;}} Invalidate ();} Public string[] Getitemcolors () {return itemcolors;}  /** * @Title: Setitemsvalues * @Description: Set individual pie pieces data * @param items * @throws */public void setitemsvalues (double[] items) {if ((items = null) && (items.length > 0)) {itemvaluestemp = items;//resets the total value, defaults to all values and resettotal (); Refreshitemsa NGS (); setitemcolors (itemcolors);} Invalidate ();} Public double[] Getitemsvalues () {return itemvaluestemp;} public void Settotal (int. total) {this.total = Total;resettotal (); invalidate ();} Public Double Gettotal () {return total;} /** * @Title: setanimenabled * @Description: Set whether rotate animation is turned on * @param isanimenabled * @throws */public void setanimenabled (bool Ean isanimenabled) {this.isanimenabled = Isanimenabled;invalidate ();} public Boolean isanimenabled () {return isanimenabled;} public void Setmovespeed (float movespeed) {if (Movespeed < 1F) {movespeed = 1F;} if (Movespeed > 5.0F) {movespeed = 5.0F;} This.movespeed = Movespeed;} public float Getmovespeed () {if (isanimenabled ()) {return movespeed;} return 0.0F;}  /** * @Title: Setshowitem * @Description: Rotate to item at specified position * @param position * position * @param anim * Animation * @param Listen * Whether to set listener * @throws */public void setshowitem (int position, Boolean anim) {if (itemsvalues! = N ull) && (Position < itemsvalues.length) && (position >= 0)) {//Get the angle that needs to be rotated Rotateendang = Getlastrotat Estartangle (position); itempostion = Position;if (anim) {Rotatestartang = 0.0f;if (Rotateendang > 0.0F) {//If the rotation angle is greater than 0, the clockwise rotation isclockwise = true;} else {//if less than 0 rotates counterclockwise isclockwise = false;} Start rotation isrotating = true;} else {Rotatestartang = Rotateendang;} If there is a listener if (null! = Itemselectedlistener) {itemselectedlistener.onpiechartitemselected (position,itemcolors[ Position], Itemsvalues[position],itemspercent[position],getanimtime (Math.Abs (Rotateendang-rotatestartang)));} Start Rotation piegraphhandler.postdelayed (this, 1L);}} private float getlastrotatestartangle (int position) {Float result = 0.0f;//get rotation angle, fix result = itemsstartangle[according to docking position Position] + itemsangle[position]/2.0f+ getstoppositionangle (); if (result >= 360.0F) {result = 360.0F;} If (result <= 180.0F) result =-result;else {result = 360.0f-result;} return result;}  /** * @Title: Getstoppositionangle * @Description: Fixed rotation angle according to docking position * @return * @throws */private float getstoppositionangle () {Float Resultangle = 0.0f;switch (stopposition) {case To_right:resultangle = 0.0f;break;case To_left:resultangle = 180.0F ; Break;case To_top:resultangle = 90.0f;breaK;case to_bottom:resultangle = 270.0f;break;} return resultangle;} public int Getshowitem () {return itempostion;} public void setstopposition (int stopposition) {this.stopposition = stopposition;} public int getstopposition () {return stopposition;}  /** * @Title: Refreshitemsangs * @Description: Initialize various angles * @throws */private void refreshitemsangs () {if (itemvaluestemp! = NULL) && (itemvaluestemp.length > 0)) {//If a total value is larger than the set's total value, then we automatically add a module out (almost no such case) if (Gettotal () > Getallsizes ()) {itemsvalues = new Double[itemvaluestemp.length + 1];for (int i = 0; i < itemvaluestemp.length; i++) {It Emsvalues[i] = Itemvaluestemp[i];} itemsvalues[(itemsvalues.length-1)] = (Gettotal ()-getallsizes ());} else {itemsvalues = new double[itemvaluestemp.length];itemsvalues = itemvaluestemp;} Start assigning values to each module itemspercent = new Float[itemsvalues.length];itemsstartangle = new Float[itemsvalues.length];itemsangle = New Float[itemsvalues.length];float startangle = 0.0f;for (int i = 0; i < itemsvalues. length; i++) {Itemspercent[i] = ((float) (itemsvalues[i] * 1.0d/gettotal () * 1.0D));} for (int i = 0; i < itemspercent.length; i++) {Itemsangle[i] = (360.0F * itemspercent[i]); if (i! = 0) {itemsstartangle[ I] = startangle + itemsangle[i-1];startangle = 360.0F * itemspercent[(i-1)] + startangle;} else {//android default start position is set to the right level, and the default docking position is initialized to the right. Interested students can modify itemsstartangle[i according to their preferences] =-itemsangle[i]/2;startangle = Itemsstartangle[i];}}} /** * Drawing */protected void OnDraw (canvas canvas) {super.ondraw (canvas);//Pie radius plus ring radius float Realradius = radius + strokewidth;  Paint paint = new paint ();p Aint.setantialias (true), float linelength = 2.0F * radius + strokewidth;if (strokewidth! = 0.0F) {//Hollow brush, first draw outer ring Paint.setstyle (Paint.Style.STROKE);p Aint.setcolor (Color.parsecolor (Loopstrokecolor)); Paint.setstrokewidth (strokewidth); Canvas.drawcircle (Realradius, Realradius, realRadius-5, paint);} if (itemsangle! = null) && (Itemsstartangle! = null)) {//Rotation angle canvas.rotate (Rotatestartang, Realradius, Realradius);//Set pie chart Rectangle RECTF Oval = new RECTF (Strokewidth, Strokewidth, linelength,linelength);//start drawing each sector for (int i = 0; i < Itemsangle.length; i++) {oval = new RECTF (Strokewidth, Strokewidth, linelength,linelength);//Draw Entity Paint.setstyle (Paint.Style.FILL) first; Paint.setcolor (Color.parsecolor (Itemcolors[i])) Canvas.drawarc (Oval, Itemsstartangle[i], itemsangle[i], True, paint);//redraw The Hollow body Stroke Paint.setstyle (Paint.Style.STROKE);p aint.setstrokewidth (STROKEWIDTH/2);p Aint.setcolor ( Color.White); Canvas.drawarc (oval, Itemsstartangle[i], itemsangle[i], true,paint);}} The Small Circle Paint.setstyle (Paint.Style.FILL);p Aint.setcolor (Color.ltgray), Canvas.drawcircle (Realradius, Realradius, SCREENUTIL.DIP2PX (GetContext (), +), paint);//Stroke Paint.setstyle (Paint.Style.STROKE);p Aint.setcolor (Color.White); Paint.setstrokewidth (strokewidth); Canvas.drawcircle (Realradius, realradius,screenutil.dip2px (GetContext (), 40), paint);} /** * Touch Event */public Boolean ontouchevent (Motionevent event) {if (!isrotating) && (itemsvalues! = null) && (itemsvalues.length > 0)) {float X1 = 0.0f;float y1 = 0.0f;switch (Event.getaction ()) {//press case  MotionEvent.ACTION_DOWN:x1 = Event.getx (), y1 = Event.gety (), Float r = radius + strokewidth;if ((x1-r) * (x1-r) + (Y1- R) * (Y1-R)-R * R <= 0.0F) {//get position int position = Getshowitem (Gettouchedpointangle (R, R, X1,y1));//rotate to specified position setshow Item (position, isanimenabled ());} Break;}} Return Super.ontouchevent (event);} /** * @Title: Gettouchedpointangle * @Description: Calculate Touch Angle * @param radiusx * Center * @param radiusy * Circle  Heart * @param x1 * Touch Point * @param y1 * Touch point * @return * @throws */private float gettouchedpointangle (float RadiusX, float radiusy, float x1,float y1) {float Differentx = x1-radiusx;float Differenty = y1-radiusy;double A = 0. 0d;double t = differenty/math.sqrt (DIFFERENTX * differentx + differenty * differenty); if (Differentx > 0.0F) {//0~90i F (Differenty > 0.0F) a = 6.283185307179586d-math.asin (t); else//270~360a =-math.asin (t);} else if (Differenty > 0.0F)//90~180a = 3.141592653589793D + math.asin (t); else {//180~270a = 3.141592653589793D + Math . ASIN (t);} return (float) (360.0d-a * 180.0d/3.141592653589793d% 360.0D);}  /** * @Title: Getshowitem * @Description: Get touch position * @param touchangle * Touch Position angle * @return * @throws */private int Getshowitem (float touchangle) {int position = 0;for (int i = 0; i < itemsstartangle.length; i++) {if (I! = Itemsstarta NGLE.LENGTH-1) {if ((Touchangle >= itemsstartangle[i]) && (Touchangle < itemsstartangle[(i + 1)])) {Positio n = i;break;}} else if ((Touchangle > itemsstartangle[(itemsstartangle.length-1)) && (Touchangle < itemsstartangle[0]) ) {position = itemsvalues.length-1;} else {//If the touch position is not correct, rotate to the maximum worthwhile position position = Getpointitem (Itemsstartangle);}} return position;} private int Getpointitem (float[] startangle) {int item = 0;float TEMP = startangle[0];for (int i = 0; i < Startangle.le Ngth-1; i++) {if (Startangle[(i + 1)]-temp > 0.0F) temp = startangle[i];else {return i;}} return item;} protected void Ondetachedfromwindow () {Super.ondetachedfromwindow ();p iegraphhandler.removecallbacks (this);} protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, Heightmeasurespec), Float widthheight = 2.0F * (radius + strokewidth + 1.0F);//Reset view's wide-height setmeasureddimension ((int) widthh eight, (int) widthheight);} /** * Rotation action */public void run () {if (isclockwise) {//clockwise rotation Rotatestartang + = movespeed;invalidate ();p iegraphhandler.postde Layed (this, 10L), if (Rotatestartang-rotateendang >= 0.0F) {Rotatestartang = 0.0f;//stop animation If you have moved to the specified position Piegraphhandler . Removecallbacks (this);//reset each module starting angle value Resetstartangle (rotateendang); isrotating = false;}} else {//counterclockwise rotation Rotatestartang-= movespeed;invalidate ();p iegraphhandler.postdelayed (this, 10L); if (Rotatestartang- Rotateendang <= 0.0F) {Rotatestartang = 0.0f;piegraphhandler.removecallbacks (this); Resetstartangle (rotateEndAng); isrotating = false;}}} Private float getanimtime (float ang) {return (int) Math.floor (ang/getmovespeed () * 10.0F);}  /** * @Title: Resetstartangle * @Description: Reset Module Angle * @param angle * @throws */private void Resetstartangle (float angle) {for (int i = 0; i < itemsstartangle.length; i++) {Float Newstartangle = Itemsstartangle[i] + angle;if (newstartangle < 0.0F) Itemsstartangle[i] = (Newstartangle + 360.0F), else if (Newstartangle > 360.0F) itemsstartangle[i] = (Newstart angle-360.0f); Elseitemsstartangle[i] = Newstartangle;}}  /** * @Title: Setdefaultcolor * @Description: Set Default color * @throws */private void Setdefaultcolor () {if (itemsvalues! = null) && (Itemsvalues.length > 0) && (itemcolors = = null)) {itemcolors = new string[itemsvalues.length];if (i Temcolors.length <= default_items_colors.length) {system.arraycopy (default_items_colors, 0, itemColors, 0, Itemcolors.length);} else {int multiple = Itemcolors.length/default_items_colors.length;int difference = itemcolors.length% default_items_colors.length;for (int a = 0; a < multiple; a++) {system.arraycopy (DEFAULT_ITEMS_ COLORS, 0, Itemcolors, a * default_items_colors.length,default_items_colors.length);} if (Difference > 0) system.arraycopy (default_items_colors, 0, Itemcolors,multiple * default_items_colors.length, difference);}}} /** * @Title: Setdifferentcolor * @Description: Replenishment color * @throws */private void Setdifferentcolor () {if (itemsvalues! = nul L) && (Itemsvalues.length > Itemcolors.length)) {string[] preitemcolors = new String[itemcolors.length]; Preitemcolors = Itemcolors;int Leftall = itemsvalues.length-itemcolors.length;itemcolors = new String[ Itemsvalues.length]; System.arraycopy (preitemcolors, 0, Itemcolors, 0,preitemcolors.length); if (Leftall <= default_items_colors.length ) {system.arraycopy (default_items_colors, 0, Itemcolors,preitemcolors.length, leftall);} else {int multiple = Leftall/default_items_colors.length;int left = leftall% Default_items_colors.length;for (int a = 0; a < multiple; a++) {system.arraycopy (default_items_colors, 0, Itemcolors, a * DEFAULT_ITEMS_COLORS.L Ength,default_items_colors.length);} if (Left > 0) {system.arraycopy (default_items_colors, 0, Itemcolors,multiple * default_items_colors.length, left);}} preitemcolors = null;}} /** * @Title: Resettotal * @Description: Reset Total value * @throws */private void Resettotal () {Double totalsizes = getallsizes (); if (Gettotal () < totalsizes) total = totalsizes;}  Private double getallsizes () {Float Tempall = 0.0f;if ((itemvaluestemp! = null) && (itemvaluestemp.length > 0)) {for (double itemsize:itemvaluestemp) {tempall + = ItemSize;}} return tempall;} public void Setitemselectedlistener (Onpiegraphitemselectedlistener itemselectedlistener) { This.itemselectedlistener = Itemselectedlistener;}}

The view of the Custom View feature report class is done. The blogger has not written a custom line chart. But to learn the two graphics, and then go to write their own line chart I think it is not difficult.

There are also 2 issues of custom view in follow-up. The first issue is about customizing the GridView (You can drag the GridView, but not with the other kind of drag item on the web, but instead drag the content inside the item to toggle the position), the first issue is about custom ViewGroup (similar to the linear layout, the relative layout kind, Can be added to the inside of the control). Hope to be able to help people who see this article.









Android Developer's Custom view feature (ii): Custom pie chart

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.