Android custom Statistical Chart (bar chart, line chart, pie chart)
Recently, due to project requirements, I have studied some statistical charts. At the beginning, I read many blog posts, most of which reference third-party libraries. Although simple,
Easy to use, but the function is too rigid and many requirements cannot be met. Therefore, after research, you can use the canvas in the View to create a new drawing.
Statistical Chart. First, take a few screenshots.
Click here to download (0 points for download)
I. demo Structure
Three fragment (v4) are nested in an activity, which uses viewpager to slide the page. below is the structure of the entire project:
Ii. Core code
The first is MainActivity. In this demo, only one activity is used. Now, multiple fragment embedded in an activity is very popular,
Many Android applications use this layout, such as QQ. This saves space waste.
Package com. example. statisticalchart; import android. support. v4.app. fragment; import android. support. v4.app. fragmentActivity; import android. support. v4.app. fragmentPagerAdapter; import android. support. v4.view. viewPager; import android. OS. bundle; import java. util. arrayList; import java. util. list; public class MainActivity extends FragmentActivity {private ViewPager viewPager; private List
Fragments; private FragmentPagerAdapter adapter; // sets whether to display the animation. To prevent the animation from being enabled during creation, use the following three parameters for determination, the animation public static int flag1 = 2; public static int flag2 = 1; public static int flag3 = 1; @ Overrideprotected void onCreate (Bundle savedInstanceState) is displayed only after the view is viewed) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); initView ();} private void initView () {viewPager = (ViewPager) findViewById (R. id. record_viewpager); fragments = new ArrayList
(); RecordPager1 recordPager1 = new RecordPager1 (); RecordPager2 recordPager2 = new RecordPager2 (); RecordPager3 recordPager3 = new RecordPager3 (); fragments. add (recordPager1); fragments. add (recordPager2); fragments. add (recordPager3); adapter = new FragmentPagerAdapter (getSupportFragmentManager () {@ Overridepublic Fragment getItem (int position) {return fragments. get (position) ;}@ Overridepublic int getCount () {return fragments. size () ;}}; viewPager. setAdapter (adapter); viewPager. setOnPageChangeListener (new ViewPager. onPageChangeListener () {@ Overridepublic void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) {}@ Overridepublic void onPageSelected (int position) {if (position = 0 & flag1 = 1) {flag1 = 2; fragments. get (0 ). onResume (); flag1 = 3;} if (position = 1 & flag2 = 1) {flag2 = 2; fragments. get (1 ). onResume (); flag2 = 3;} if (position = 2 & flag3 = 1) {flag3 = 2; fragments. get (2 ). onResume (); flag3 = 3 ;}@ Overridepublic void onPageScrollStateChanged (int state ){}});}}
The following are the three most important classes in this project: HistogramView, LineChartView, and PinChart. The three classes inherit the View class, recompose the chart, and draw the column chart, line chart, and pie chart respectively. Then, the code of the three classes is given:
Package com. example. statisticalchart; import android. annotation. suppressLint; 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. paint. align; import android. graphics. rect; import android. OS. logoff; import android. util. attributeSet; import android Oid. view. motionEvent; import android. view. view; import android. view. animation. animation; import android. view. animation. transformation; public class HistogramView extends View {private Paint xLinePaint; // axis Paint: private Paint hLinePaint; // horizontal coordinate axis dotted line Paint private Paint titlePaint; // Paint brush private paint for text painting; // The style information private int [] progress = {2000,500 0, 6000,800 0, 500,600 0, 9000} of the rectangular Paint bar chart }; // 7 //, display Shows the data private int [] aniProgress of each column; // The animation value private final int TRUE = 1; // display the number private int [] text on the bar chart; // set the click event to display the information of which column is private Bitmap bitmap; // The number of private String [] ySteps on the left of the coordinate axis; // The number of weeks at the bottom of the coordinate axis private String [] xWeeks; private int flag; // whether to use the animation private HistogramAnimation ani; public HistogramView (Context context) {super (context ); init ();} public HistogramView (Context context, AttributeSet attrs) {super (co Ntext, attrs); init ();} private void init () {ySteps = new String [] {"10 k", "7.5 k", "5 k ", "2.5 k", "0"}; xWeeks = new String [] {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday ", "Saturday", "Sunday"}; text = new int [] {0, 0, 0, 0, 0}; aniProgress = new int [] {0, 0, 0, 0, 0, 0, 0}; ani = new HistogramAnimation (); ani. setDuration (2000); xLinePaint = new Paint (); hLinePaint = new Paint (); titlePaint = new Paint (); paint = new Pa Int (); // set the color xLinePaint for the paint brush. setColor (Color. DKGRAY); hLinePaint. setColor (Color. LTGRAY); titlePaint. setColor (Color. BLACK); // load the drawing bitmap = BitmapFactory. decodeResource (getResources (), R. drawable. column);} public void start (int flag) {this. flag = flag; this. startAnimation (ani) ;}@ SuppressLint ("DrawAllocation") @ Overrideprotected void onDraw (Canvas canvas) {super. onDraw (canvas); int width = getWidth (); int heig Ht = getHeight ()-dp2px (50); // draw the bottom line canvas. drawLine (dp2px (30), height + dp2px (3), width-dp2px (30), height + dp2px (3), xLinePaint ); int leftHeight = height-dp2px (5); // The height of the Left peripheral: int hPerHeight = leftHeight/4; // hLinePaint. setTextAlign (Align. CENTER); // set four dotted lines for (int I = 0; I <4; I ++) {canvas. drawLine (dp2px (30), dp2px (10) + I * hPerHeight, width-dp2px (30), dp2px (10) + I * hPerHeigh T, hLinePaint);} // draws the Y-week titlePaint. setTextAlign (Align. RIGHT); titlePaint. setTextSize (sp2px (12); titlePaint. setAntiAlias (true); titlePaint. setStyle (Paint. style. FILL); // set the left digit for (int I = 0; I <ySteps. length; I ++) {canvas. drawText (ySteps [I], dp2px (25), dp2px (13) + I * hPerHeight, titlePaint );} // draw X-week coordinates int xAxisLength = width-dp2px (30); int columCount = xWeeks. length + 1; int step = xAxisLengt H/columCount; // set the bottom number for (int I = 0; I <columCount-1; I ++) {// text, baseX, baseY, textPaintcanvas. drawText (xWeeks [I], dp2px (25) + step * (I + 1), height + dp2px (20), titlePaint);} // draw a rectangle if (aniProgress! = Null & aniProgress. length> 0) {for (int I = 0; I <aniProgress. length; I ++) {// cyclically traverse the seven bar charts and draw the int value = aniProgress [I]; paint. setAntiAlias (true); // anti-aliasing effect paint. setStyle (Paint. style. FILL); paint. setTextSize (sp2px (15); // specifies the font size of paint. setColor (Color. parseColor ("#6 DCAEC"); // font color Rect rect = new Rect (); // rect of the column chart shape. left = step * (I + 1); rect. right = dp2px (30) + step * (I + 1); int rh = (int) (leftHeig Ht-leftHeight * (value/10000.0); rect. top = rh + dp2px (10); rect. bottom = height; canvas. drawBitmap (bitmap, null, rect, paint); // whether to display the number above the bar chart if (this. text [I] = TRUE) {canvas. drawText (value + "", dp2px (15) + step * (I + 1)-dp2px (15), rh + dp2px (5), paint );}}}} private int dp2px (int value) {float v = getContext (). getResources (). getDisplayMetrics (). density; return (int) (v * value + 0.5f);} private Int sp2px (int value) {float v = getContext (). getResources (). getDisplayMetrics (). scaledDensity; return (int) (v * value + 0.5f);}/*** set the click event to show the number */public boolean onTouchEvent (MotionEvent event) {int step = (getWidth ()-dp2px (30)/8; int x = (int) event. getX (); for (int I = 0; I <7; I ++) {if (x> (dp2px (15) + step * (I + 1) -dp2px (15) & x <(dp2px (15) + step * (I + 1) + dp2px (15) {text [I] = 1; for (int j = 0; j <7; j ++) {if (I! = J) {text [j] = 0 ;}} if (logoff. getmainlogoff () = logoff. mylodate () {invalidate () ;}else {postInvalidate () ;}} return super. onTouchEvent (event);}/*** an animation class integrating Animation ** @ author Li Xiaochao */private class HistogramAnimation extends animation {protected void applyTransformation (float interpolatedTime, Transformation t) {super. applyTransformation (interpolatedTime, t); if (interpolatedTime <1.0f & flag = 2) {for (int I = 0; I <aniProgress. length; I ++) {aniProgress [I] = (int) (progress [I] * interpolatedTime) ;}} else {for (int I = 0; I <aniProgress. length; I ++) {aniProgress [I] = progress [I] ;}} invalidate ();}}}
Package com. example. statisticalchart; import android. annotation. suppressLint; 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. paint. align; import android. graphics. path; import android. graphics. porterDuff; import android. graphics. porterDuff Xfermode; import android. graphics. rect; import android. util. attributeSet; import android. util. log; import android. view. view; import android. view. animation. animation; import android. view. animation. transformation; public class LineChartView extends View {private Paint rectPaint; // set to white on the left to display the number table private Paint hLinePaint; // the dotted line inside the horizontal axis brush private Paint titlePaint; // Paint brush for painting text private Paint linePaint; private Paint pa Int; // private int [] text for the style information of the rectangular brush bar chart; // int x, y, preX, preY of the broken line; // The number of private Bitmap mBitmap on the left of the coordinate axis; // number of weeks at the bottom of the coordinate axis private String [] str = {"62", "72", "82", "92", "102", "112 ", "122", "132", "142"}; private HistogramAnimation ani; private int flag; public LineChartView (Context context) {super (context); init (context, null);} public LineChartView (Context context, AttributeSet attrs) {super (context, attr S); // TODO Auto-generated constructor stubinit (context, attrs);} private void init (Context context, AttributeSet attrs) {text = new int [] {6, 5, 5, 4, 5, 3, 2, 3, 1, 1}; ani = new HistogramAnimation (); ani. setDuration (4000); rectPaint = new Paint (); titlePaint = new Paint () ;}@ Overrideprotected void onDraw (Canvas canvas) {super. onDraw (canvas); linePaint = new Paint (); // titlePaint. setAntiAlias (true); Rec T bundle1 = new Rect (); Rect bundle2 = new Rect (); hLinePaint = new Paint (); int perWidth = getWidth ()/10; // divide the width into 10 parts: int hPerHeight = getHeight ()/10; // divide the height into 10 parts: rectPaint. setColor (Color. WHITE); canvas. drawRect (0, 0, dp2px (30), getHeight (), rectPaint); // draw a white area Path path = new Path (); // line chart path mBitmap = Bitmap. createBitmap (getWidth (), getHeight (), Bitmap. config. ARGB_8888); Canvas mCanvas = new Canvas (MBitmap); for (int I = 0; I <10; I ++) {// draw an X-ray and display the corresponding value hLinePaint on the left. setTextAlign (Align. CENTER); hLinePaint. setColor (Color. WHITE); y = I * hPerHeight; if (I = 2) {hLinePaint. setStrokeWidth (4); for (int j = 0; j <10; j ++) {canvas. drawLine (dp2px (30) + j * perWidth, y, dp2px (28) + (j + 1) * perWidth, y, hLinePaint);} titlePaint. setTextSize (sp2px (20); titlePaint. getTextBounds (str [I-1], 0, str [I-1]. len Dependencies (), bundle1); canvas. drawText (str [I-1], dp2px (25)-bundle1.width (), I * hPerHeight + (bundle1.height ()/2), titlePaint);} else {hLinePaint. setStrokeWidth (1); canvas. drawLine (dp2px (30), y, getWidth (), y, hLinePaint); if (I! = 0) {titlePaint. setTextSize (sp2px (15); titlePaint. getTextBounds (str [I-1], 0, str [I-1]. length (), bundle2); canvas. drawText (str [I-1], dp2px (25)-bundle2.width (), I * hPerHeight + (bundle2.height ()/2), titlePaint );}} x = I * perWidth + dp2px (30); if (I = 0) {path. moveTo (x, text [I] * hPerHeight);} else {path. lineTo (x, text [I] * hPerHeight);} linePaint. setColor (Color. parseColor ("# bb2222"); linePain T. setAntiAlias (true); paint = new Paint (); paint. setColor (Color. RED); paint. setStyle (Paint. style. STROKE); paint. setStrokeWidth (dp2px (1); if (I! = 0) {mCanvas. drawCircle (x, text [I] * hPerHeight, dp2px (3), linePaint);} paint. setXfermode (new porterduxfermode (PorterDuff. mode. DST_OVER); mCanvas. drawPath (path, paint);} paint. setXfermode (new porterduxfermode (PorterDuff. mode. DST_OUT); paint. setStyle (Paint. style. FILL); mCanvas. drawRect (preX + dp2px (30), 0, getWidth (), getHeight (), paint); canvas. drawBitmap (mBitmap, 0, 0, null); // Log. I ("tag", "onDraw () 1111");} private int dp2px (int value) {float v = getContext (). getResources (). getDisplayMetrics (). density; return (int) (v * value + 0.5f);} private int sp2px (int value) {float v = getContext (). getResources (). getDisplayMetrics (). scaledDensity; return (int) (v * value + 0.5f);} public void start (int flag) {startAnimation (ani); this. flag = flag;}/*** an animation class integrating Animation ** @ author */private class HistogramAnimation extends animation {@ Overrideprotected void applyTransformation (float interpolatedTime, Transformation t) {super. applyTransformation (interpolatedTime, t); if (interpolatedTime <1.0f & flag = 2) {preX = (int) (getWidth ()-dp2px (30 )) * interpolatedTime);} else {preX = getWidth ();} invalidate ();}}}
Package com. example. statisticalchart; import android. content. context; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. graphics. porterDuff; import android. graphics. porterduxfermode; import android. graphics. rect; import android. graphics. rectF; import android. util. attributeSet; import android. util. log; import android. view. view; import android. view. animation. animation; import android. view. animation. transformation; public class PinChart extends View {static Canvas c; private Paint [] mPaints; private RectF mBigOval; float [] mSweep = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; private int preWidth; private mAnimation ani; private int flag; private int centerX; private int centerY; int valueX; int valueY; public static float [] humidity = {110, 60, 50, 50, 40, 30, 10, 10}; private String str [] = {"Data 24% ", "Data 19%", "Data 21%", "Other 18%", "Data 3%", "Data 3%", "Data 4%", "Data 6% "}; private final String color [] = {"#2cbae7", "# ffa500", "# ff5b3b", "#9fa0a4", "#6a71e5", "# f83f5d ", "#64a300", "#64ef85"}; public PinChart (Context context) {super (context); initView ();} public PinChart (Context context Context, AttributeSet recognition) {super (context, recognition); initView ();} private void initView () {ani = new mAnimation (); ani. setDuration (2000) ;}@ Overrideprotected void onDraw (Canvas canvas) {canvas. drawColor (Color. TRANSPARENT); // set the background color (TRANSPARENT) mPaints = new Paint [humidity. length]; for (int I = 0; I
The above are all the core code, not all of which will not be pasted out. Interested friends can download them for research.