Android自定义统计图(柱状图,折线图,饼状图)
来源:互联网 发布:ipad壁纸 知乎 编辑:程序博客网 时间:2024/05/17 14:20
最近由于项目需要,研究了一些统计图的做法,开始时,看了很多博文,大部分都是引用第三方的库,虽然简单,
易上手,但是功能太死板,有很多要求都是不能满足的,所以经过研究,自己使用View中的canvas重新绘图制作
统计图。首先上几张的效果图吧。
点击这里下载(0分下载)
一、demo的结构
一个activity中嵌套了三个fragment(v4),是用viewpager对页面进行滑动,下面是整个项目的结构:
二、核心代码
首先是MainActivity,这个demo中只使用到一个activity,现在一个activity中镶嵌多个fragment很火,
很多Android应用都在使用这个布局,例如微信,QQ等。这样做节省了空间上的浪费。
- 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<Fragment> fragments;
- private FragmentPagerAdapter adapter;
- // 设置是否显示动画,为了防止在创建时就开启动画,用以下三个参数做了判断,只有当看到视图后才会显示动画
- public static int flag1 = 2;
- public static int flag2 = 1;
- public static int flag3 = 1;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initView();
- }
- private void initView() {
- viewPager = (ViewPager) findViewById(R.id.record_viewpager);
- fragments = new ArrayList<Fragment>();
- 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()) {
- @Override
- public Fragment getItem(int position) {
- return fragments.get(position);
- }
- @Override
- public int getCount() {
- return fragments.size();
- }
- };
- viewPager.setAdapter(adapter);
- viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
- @Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
- }
- @Override
- public 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;
- }
- }
- @Override
- public void onPageScrollStateChanged(int state) {
- }
- });
- }
- }
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<Fragment> fragments; private FragmentPagerAdapter adapter; // 设置是否显示动画,为了防止在创建时就开启动画,用以下三个参数做了判断,只有当看到视图后才会显示动画 public static int flag1 = 2; public static int flag2 = 1; public static int flag3 = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { viewPager = (ViewPager) findViewById(R.id.record_viewpager); fragments = new ArrayList<Fragment>(); 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()) { @Override public Fragment getItem(int position) { return fragments.get(position); } @Override public int getCount() { return fragments.size(); } }; viewPager.setAdapter(adapter); viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public 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; } } @Override public void onPageScrollStateChanged(int state) { } }); }}
接下来是这个项目中最主要的三个类:HistogramView、LineChartView、PinChart。这三个类继承View类,重新构图,分别画成了柱状图,折线图,饼状图,然后给出三个类的代码:
- 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.Looper;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.animation.Animation;
- import android.view.animation.Transformation;
- public class HistogramView extends View {
- private Paint xLinePaint;// 坐标轴 轴线 画笔:
- private Paint hLinePaint;// 坐标轴水平内部 虚线画笔
- private Paint titlePaint;// 绘制文本的画笔
- private Paint paint;// 矩形画笔 柱状图的样式信息
- private int[] progress = { 2000, 5000, 6000, 8000, 500, 6000, 9000 };// 7
- // 条,显示各个柱状的数据
- private int[] aniProgress;// 实现动画的值
- private final int TRUE = 1;// 在柱状图上显示数字
- private int[] text;// 设置点击事件,显示哪一条柱状的信息
- private Bitmap bitmap;
- // 坐标轴左侧的数标
- private String[] ySteps;
- // 坐标轴底部的星期数
- private String[] xWeeks;
- private int flag;// 是否使用动画
- private HistogramAnimation ani;
- public HistogramView(Context context) {
- super(context);
- init();
- }
- public HistogramView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- private void init() {
- ySteps = new String[] { “10k”, “7.5k”, “5k”, “2.5k”, “0” };
- xWeeks = new String[] { “周一”, “周二”, “周三”, “周四”, “周五”, “周六”, “周日” };
- text = new int[] { 0, 0, 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 Paint();
- // 给画笔设置颜色
- xLinePaint.setColor(Color.DKGRAY);
- hLinePaint.setColor(Color.LTGRAY);
- titlePaint.setColor(Color.BLACK);
- // 加载画图
- bitmap = BitmapFactory
- .decodeResource(getResources(), R.drawable.column);
- }
- public void start(int flag) {
- this.flag = flag;
- this.startAnimation(ani);
- }
- @SuppressLint(“DrawAllocation”)
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int width = getWidth();
- int height = getHeight() - dp2px(50);
- // 绘制底部的线条
- canvas.drawLine(dp2px(30), height + dp2px(3), width - dp2px(30), height
- + dp2px(3), xLinePaint);
- int leftHeight = height - dp2px(5);// 左侧外周的 需要划分的高度:
- int hPerHeight = leftHeight / 4;// 分成四部分
- hLinePaint.setTextAlign(Align.CENTER);
- // 设置四条虚线
- for (int i = 0; i < 4; i++) {
- canvas.drawLine(dp2px(30), dp2px(10) + i * hPerHeight, width
- - dp2px(30), dp2px(10) + i * hPerHeight, hLinePaint);
- }
- // 绘制 Y 周坐标
- titlePaint.setTextAlign(Align.RIGHT);
- titlePaint.setTextSize(sp2px(12));
- titlePaint.setAntiAlias(true);
- titlePaint.setStyle(Paint.Style.FILL);
- // 设置左部的数字
- for (int i = 0; i < ySteps.length; i++) {
- canvas.drawText(ySteps[i], dp2px(25), dp2px(13) + i * hPerHeight,
- titlePaint);
- }
- // 绘制 X 周 做坐标
- int xAxisLength = width - dp2px(30);
- int columCount = xWeeks.length + 1;
- int step = xAxisLength / columCount;
- // 设置底部的数字
- for (int i = 0; i < columCount - 1; i++) {
- // text, baseX, baseY, textPaint
- canvas.drawText(xWeeks[i], dp2px(25) + step * (i + 1), height
- + dp2px(20), titlePaint);
- }
- // 绘制矩形
- if (aniProgress != null && aniProgress.length > 0) {
- for (int i = 0; i < aniProgress.length; i++) {// 循环遍历将7条柱状图形画出来
- int value = aniProgress[i];
- paint.setAntiAlias(true);// 抗锯齿效果
- paint.setStyle(Paint.Style.FILL);
- paint.setTextSize(sp2px(15));// 字体大小
- paint.setColor(Color.parseColor(”#6DCAEC”));// 字体颜色
- Rect rect = new Rect();// 柱状图的形状
- rect.left = step * (i + 1);
- rect.right = dp2px(30) + step * (i + 1);
- int rh = (int) (leftHeight - leftHeight * (value / 10000.0));
- rect.top = rh + dp2px(10);
- rect.bottom = height;
- canvas.drawBitmap(bitmap, null, rect, paint);
- // 是否显示柱状图上方的数字
- 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);
- }
- /**
- * 设置点击事件,是否显示数字
- */
- 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 (Looper.getMainLooper() == Looper.myLooper()) {
- invalidate();
- } else {
- postInvalidate();
- }
- }
- }
- return super.onTouchEvent(event);
- }
- /**
- * 集成animation的一个动画类
- *
- * @author 李垭超
- */
- 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.Rect;import android.os.Looper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.animation.Animation;import android.view.animation.Transformation;public class HistogramView extends View { private Paint xLinePaint;// 坐标轴 轴线 画笔: private Paint hLinePaint;// 坐标轴水平内部 虚线画笔 private Paint titlePaint;// 绘制文本的画笔 private Paint paint;// 矩形画笔 柱状图的样式信息 private int[] progress = { 2000, 5000, 6000, 8000, 500, 6000, 9000 };// 7 // 条,显示各个柱状的数据 private int[] aniProgress;// 实现动画的值 private final int TRUE = 1;// 在柱状图上显示数字 private int[] text;// 设置点击事件,显示哪一条柱状的信息 private Bitmap bitmap; // 坐标轴左侧的数标 private String[] ySteps; // 坐标轴底部的星期数 private String[] xWeeks; private int flag;// 是否使用动画 private HistogramAnimation ani; public HistogramView(Context context) { super(context); init(); } public HistogramView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { ySteps = new String[] { "10k", "7.5k", "5k", "2.5k", "0" }; xWeeks = new String[] { "周一", "周二", "周三", "周四", "周五", "周六", "周日" }; text = new int[] { 0, 0, 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 Paint(); // 给画笔设置颜色 xLinePaint.setColor(Color.DKGRAY); hLinePaint.setColor(Color.LTGRAY); titlePaint.setColor(Color.BLACK); // 加载画图 bitmap = BitmapFactory .decodeResource(getResources(), R.drawable.column); } public void start(int flag) { this.flag = flag; this.startAnimation(ani); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); int height = getHeight() - dp2px(50); // 绘制底部的线条 canvas.drawLine(dp2px(30), height + dp2px(3), width - dp2px(30), height + dp2px(3), xLinePaint); int leftHeight = height - dp2px(5);// 左侧外周的 需要划分的高度: int hPerHeight = leftHeight / 4;// 分成四部分 hLinePaint.setTextAlign(Align.CENTER); // 设置四条虚线 for (int i = 0; i < 4; i++) { canvas.drawLine(dp2px(30), dp2px(10) + i * hPerHeight, width - dp2px(30), dp2px(10) + i * hPerHeight, hLinePaint); } // 绘制 Y 周坐标 titlePaint.setTextAlign(Align.RIGHT); titlePaint.setTextSize(sp2px(12)); titlePaint.setAntiAlias(true); titlePaint.setStyle(Paint.Style.FILL); // 设置左部的数字 for (int i = 0; i < ySteps.length; i++) { canvas.drawText(ySteps[i], dp2px(25), dp2px(13) + i * hPerHeight, titlePaint); } // 绘制 X 周 做坐标 int xAxisLength = width - dp2px(30); int columCount = xWeeks.length + 1; int step = xAxisLength / columCount; // 设置底部的数字 for (int i = 0; i < columCount - 1; i++) { // text, baseX, baseY, textPaint canvas.drawText(xWeeks[i], dp2px(25) + step * (i + 1), height + dp2px(20), titlePaint); } // 绘制矩形 if (aniProgress != null && aniProgress.length > 0) { for (int i = 0; i < aniProgress.length; i++) {// 循环遍历将7条柱状图形画出来 int value = aniProgress[i]; paint.setAntiAlias(true);// 抗锯齿效果 paint.setStyle(Paint.Style.FILL); paint.setTextSize(sp2px(15));// 字体大小 paint.setColor(Color.parseColor("#6DCAEC"));// 字体颜色 Rect rect = new Rect();// 柱状图的形状 rect.left = step * (i + 1); rect.right = dp2px(30) + step * (i + 1); int rh = (int) (leftHeight - leftHeight * (value / 10000.0)); rect.top = rh + dp2px(10); rect.bottom = height; canvas.drawBitmap(bitmap, null, rect, paint); // 是否显示柱状图上方的数字 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); } /** * 设置点击事件,是否显示数字 */ 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 (Looper.getMainLooper() == Looper.myLooper()) { invalidate(); } else { postInvalidate(); } } } return super.onTouchEvent(event); } /** * 集成animation的一个动画类 * * @author 李垭超 */ 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.PorterDuffXfermode;
- 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;// 设置左侧为白色,显示数表
- private Paint hLinePaint;// 坐标轴水平内部 虚线画笔
- private Paint titlePaint;// 绘制文本的画笔
- private Paint linePaint;
- private Paint paint;// 矩形画笔 柱状图的样式信息
- private int[] text;// 折线的转折点
- int x, y, preX, preY;
- // 坐标轴左侧的数标
- private Bitmap mBitmap;
- // 坐标轴底部的星期数
- 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, attrs);
- // TODO Auto-generated constructor stub
- init(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();
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- linePaint = new Paint();
- //
- titlePaint.setAntiAlias(true);
- Rect bundle1 = new Rect();
- Rect bundle2 = new Rect();
- hLinePaint = new Paint();
- int perWidth = getWidth() / 10;// 将宽度分为10部分
- int hPerHeight = getHeight() / 10;// 将高度分为10部分
- rectPaint.setColor(Color.WHITE);
- canvas.drawRect(0, 0, dp2px(30), getHeight(), rectPaint);// 画一块白色区域
- Path path = new Path();// 折线图的路径
- mBitmap = Bitmap.createBitmap(getWidth(), getHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas mCanvas = new Canvas(mBitmap);
- for (int i = 0; i < 10; i++) {// 画x线,并在左侧显示相应的数值
- hLinePaint.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].length(),
- 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”));
- linePaint.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 PorterDuffXfermode(PorterDuff.Mode.DST_OVER));
- mCanvas.drawPath(path, paint);
- }
- paint.setXfermode(new PorterDuffXfermode(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;
- }
- /**
- * 集成animation的一个动画类
- *
- * @author
- */
- private class HistogramAnimation extends Animation {
- @Override
- protected 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.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.PorterDuffXfermode;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;// 设置左侧为白色,显示数表 private Paint hLinePaint;// 坐标轴水平内部 虚线画笔 private Paint titlePaint;// 绘制文本的画笔 private Paint linePaint; private Paint paint;// 矩形画笔 柱状图的样式信息 private int[] text;// 折线的转折点 int x, y, preX, preY; // 坐标轴左侧的数标 private Bitmap mBitmap; // 坐标轴底部的星期数 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, attrs); // TODO Auto-generated constructor stub init(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(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); linePaint = new Paint(); // titlePaint.setAntiAlias(true); Rect bundle1 = new Rect(); Rect bundle2 = new Rect(); hLinePaint = new Paint(); int perWidth = getWidth() / 10;// 将宽度分为10部分 int hPerHeight = getHeight() / 10;// 将高度分为10部分 rectPaint.setColor(Color.WHITE); canvas.drawRect(0, 0, dp2px(30), getHeight(), rectPaint);// 画一块白色区域 Path path = new Path();// 折线图的路径 mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas mCanvas = new Canvas(mBitmap); for (int i = 0; i < 10; i++) {// 画x线,并在左侧显示相应的数值 hLinePaint.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].length(), 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")); linePaint.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 PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); mCanvas.drawPath(path, paint); } paint.setXfermode(new PorterDuffXfermode(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; } /** * 集成animation的一个动画类 * * @author */ private class HistogramAnimation extends Animation { @Override protected 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.PorterDuffXfermode;
- 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 };
- 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[] = { “数据24%”, “数据19%”, “数据21%”, “其他18%”, “数据3%”,
- ”数据3%”, “数据4%”, “数据6%” };
- private final String color[] = { “#2cbae7”, “#ffa500”, “#ff5b3b”,
- ”#9fa0a4”, “#6a71e5”, “#f83f5d”, “#64a300”, “#64ef85” };
- public PinChart(Context context) {
- super(context);
- initView();
- }
- public PinChart(Context context, AttributeSet atr) {
- super(context, atr);
- initView();
- }
- private void initView() {
- ani = new mAnimation();
- ani.setDuration(2000);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- canvas.drawColor(Color.TRANSPARENT);// 设置背景颜色(透明)
- mPaints = new Paint[humidity.length];
- for (int i = 0; i < humidity.length; i++) {
- mPaints[i] = new Paint();
- mPaints[i].setAntiAlias(true);
- mPaints[i].setStyle(Paint.Style.FILL);
- mPaints[i].setColor(Color.parseColor(color[i]));
- }
- int cicleWidth = getWidth() - dp2px(60);
- centerX = getWidth() / 2;
- centerY = dp2px(10) + cicleWidth / 2;
- preWidth = (getWidth() - dp2px(40)) / 4;
- int half = getWidth() / 2;
- mBigOval = new RectF();// 饼图的四周边界
- mBigOval.top = dp2px(10);
- mBigOval.left = half - cicleWidth / 2;
- mBigOval.bottom = dp2px(10) + cicleWidth;
- mBigOval.right = half + cicleWidth / 2;
- float start = -180;
- Rect bounds = new Rect();
- for (int i = 0; i < humidity.length; i++) {
- canvas.drawArc(mBigOval, start, mSweep[i], true, mPaints[i]);
- if (humidity[i] > 45) {
- mPaints[i].setXfermode(new PorterDuffXfermode(
- PorterDuff.Mode.SRC_OVER));
- mPaints[i].setAntiAlias(true);
- mPaints[i].setColor(Color.WHITE);
- mPaints[i].getTextBounds(str[i], 0, str[i].length(), bounds);
- mPaints[i].setTextSize(sp2px(15));
- measureText(start + 180, humidity[i], cicleWidth / 3, i);
- canvas.drawText(str[i], valueX - mPaints[i].measureText(str[i])
- / 2, valueY + bounds.height() / 2, mPaints[i]);
- }
- start += humidity[i];
- int j = 1;
- int k;
- if (i < 4) {
- j = 0;
- k = i;
- } else {
- j = 1;
- k = i - 4;
- }
- mPaints[i] = new Paint();
- mPaints[i].setAntiAlias(true);
- mPaints[i].setStyle(Paint.Style.FILL);
- mPaints[i].setColor(Color.parseColor(color[i]));
- canvas.drawRect(new RectF(dp2px(20) + preWidth * k, cicleWidth
- + dp2px(j * 30 + 20), dp2px(20) + preWidth * (k + 1),
- cicleWidth + dp2px(50 + j * 30)), mPaints[i]);
- mPaints[i].setXfermode(new PorterDuffXfermode(
- PorterDuff.Mode.SRC_OVER));
- mPaints[i].setAntiAlias(true);
- mPaints[i].setColor(Color.WHITE);
- mPaints[i].getTextBounds(str[i], 0, str[i].length(), bounds);
- mPaints[i].setTextSize(sp2px(15));
- canvas.drawText(str[i], dp2px(20) + preWidth * k + preWidth / 2
- - mPaints[i].measureText(str[i]) / 2, cicleWidth
- + dp2px(j * 30 + 20)
- + (dp2px(30) / 2 + bounds.height() / 2), mPaints[i]);
- }
- }
- /**
- * 显示相应区域字开始的x,y坐标
- *
- * @param start
- * @param angle
- * @param radius
- * @param i
- */
- private void measureText(float start, float angle, int radius, int i) {
- float temp = start + (angle / 2);
- if (temp < 90) {
- valueX = (int) (centerX - Math.abs(radius
- * Math.sin((temp / 180) * Math.PI)));
- valueY = (int) (centerY - Math.abs(radius
- * Math.cos((temp / 180) * Math.PI)));
- } else if (temp > 90 && temp < 180) {
- temp = 180 - temp;
- valueX = centerX
- + (int) Math
- .abs((radius * Math.cos((temp / 180) * Math.PI)));
- valueY = centerY
- - (int) Math
- .abs((radius * Math.sin((temp / 180) * Math.PI)));
- } else if (temp > 180 && temp < 270) {
- temp = temp - 180;
- valueX = centerX
- + (int) Math
- .abs((radius * Math.cos((temp / 180) * Math.PI)));
- valueY = centerY
- + (int) Math
- .abs((radius * Math.sin((temp / 180) * Math.PI)));
- } else {
- temp = 360 - temp;
- valueX = centerX
- - (int) Math
- .abs((radius * Math.cos((temp / 180) * Math.PI)));
- valueY = centerY
- + (int) Math
- .abs((radius * Math.sin((temp / 180) * Math.PI)));
- }
- }
- private int sp2px(int value) {
- float v = getResources().getDisplayMetrics().scaledDensity;
- return (int) (value * v + 0.5f);
- }
- private int dp2px(int value) {
- float v = getResources().getDisplayMetrics().density;
- return (int) (value * v + 0.5f);
- }
- public void start(int flag) {
- startAnimation(ani);
- this.flag = flag;
- }
- class mAnimation extends Animation {
- @Override
- protected void applyTransformation(float interpolatedTime,
- Transformation t) {
- super.applyTransformation(interpolatedTime, t);
- if (interpolatedTime < 1.0f && flag == 2) {
- for (int i = 0; i < humidity.length; i++) {
- mSweep[i] = humidity[i] * interpolatedTime;
- }
- } else if (flag == 1) {
- for (int i = 0; i < humidity.length; i++) {
- mSweep[i] = 0;
- }
- } else {
- for (int i = 0; i < humidity.length; i++) {
- mSweep[i] = humidity[i];
- }
- }
- 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.PorterDuffXfermode;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 }; 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[] = { "数据24%", "数据19%", "数据21%", "其他18%", "数据3%", "数据3%", "数据4%", "数据6%" }; private final String color[] = { "#2cbae7", "#ffa500", "#ff5b3b", "#9fa0a4", "#6a71e5", "#f83f5d", "#64a300", "#64ef85" }; public PinChart(Context context) { super(context); initView(); } public PinChart(Context context, AttributeSet atr) { super(context, atr); initView(); } private void initView() { ani = new mAnimation(); ani.setDuration(2000); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.TRANSPARENT);// 设置背景颜色(透明) mPaints = new Paint[humidity.length]; for (int i = 0; i < humidity.length; i++) { mPaints[i] = new Paint(); mPaints[i].setAntiAlias(true); mPaints[i].setStyle(Paint.Style.FILL); mPaints[i].setColor(Color.parseColor(color[i])); } int cicleWidth = getWidth() - dp2px(60); centerX = getWidth() / 2; centerY = dp2px(10) + cicleWidth / 2; preWidth = (getWidth() - dp2px(40)) / 4; int half = getWidth() / 2; mBigOval = new RectF();// 饼图的四周边界 mBigOval.top = dp2px(10); mBigOval.left = half - cicleWidth / 2; mBigOval.bottom = dp2px(10) + cicleWidth; mBigOval.right = half + cicleWidth / 2; float start = -180; Rect bounds = new Rect(); for (int i = 0; i < humidity.length; i++) { canvas.drawArc(mBigOval, start, mSweep[i], true, mPaints[i]); if (humidity[i] > 45) { mPaints[i].setXfermode(new PorterDuffXfermode( PorterDuff.Mode.SRC_OVER)); mPaints[i].setAntiAlias(true); mPaints[i].setColor(Color.WHITE); mPaints[i].getTextBounds(str[i], 0, str[i].length(), bounds); mPaints[i].setTextSize(sp2px(15)); measureText(start + 180, humidity[i], cicleWidth / 3, i); canvas.drawText(str[i], valueX - mPaints[i].measureText(str[i]) / 2, valueY + bounds.height() / 2, mPaints[i]); } start += humidity[i]; int j = 1; int k; if (i < 4) { j = 0; k = i; } else { j = 1; k = i - 4; } mPaints[i] = new Paint(); mPaints[i].setAntiAlias(true); mPaints[i].setStyle(Paint.Style.FILL); mPaints[i].setColor(Color.parseColor(color[i])); canvas.drawRect(new RectF(dp2px(20) + preWidth * k, cicleWidth + dp2px(j * 30 + 20), dp2px(20) + preWidth * (k + 1), cicleWidth + dp2px(50 + j * 30)), mPaints[i]); mPaints[i].setXfermode(new PorterDuffXfermode( PorterDuff.Mode.SRC_OVER)); mPaints[i].setAntiAlias(true); mPaints[i].setColor(Color.WHITE); mPaints[i].getTextBounds(str[i], 0, str[i].length(), bounds); mPaints[i].setTextSize(sp2px(15)); canvas.drawText(str[i], dp2px(20) + preWidth * k + preWidth / 2 - mPaints[i].measureText(str[i]) / 2, cicleWidth + dp2px(j * 30 + 20) + (dp2px(30) / 2 + bounds.height() / 2), mPaints[i]); } } /** * 显示相应区域字开始的x,y坐标 * * @param start * @param angle * @param radius * @param i */ private void measureText(float start, float angle, int radius, int i) { float temp = start + (angle / 2); if (temp < 90) { valueX = (int) (centerX - Math.abs(radius * Math.sin((temp / 180) * Math.PI))); valueY = (int) (centerY - Math.abs(radius * Math.cos((temp / 180) * Math.PI))); } else if (temp > 90 && temp < 180) { temp = 180 - temp; valueX = centerX + (int) Math .abs((radius * Math.cos((temp / 180) * Math.PI))); valueY = centerY - (int) Math .abs((radius * Math.sin((temp / 180) * Math.PI))); } else if (temp > 180 && temp < 270) { temp = temp - 180; valueX = centerX + (int) Math .abs((radius * Math.cos((temp / 180) * Math.PI))); valueY = centerY + (int) Math .abs((radius * Math.sin((temp / 180) * Math.PI))); } else { temp = 360 - temp; valueX = centerX - (int) Math .abs((radius * Math.cos((temp / 180) * Math.PI))); valueY = centerY + (int) Math .abs((radius * Math.sin((temp / 180) * Math.PI))); } } private int sp2px(int value) { float v = getResources().getDisplayMetrics().scaledDensity; return (int) (value * v + 0.5f); } private int dp2px(int value) { float v = getResources().getDisplayMetrics().density; return (int) (value * v + 0.5f); } public void start(int flag) { startAnimation(ani); this.flag = flag; } class mAnimation extends Animation { @Override protected void applyTransformation(float interpolatedTime, Transformation t) { super.applyTransformation(interpolatedTime, t); if (interpolatedTime < 1.0f && flag == 2) { for (int i = 0; i < humidity.length; i++) { mSweep[i] = humidity[i] * interpolatedTime; } } else if (flag == 1) { for (int i = 0; i < humidity.length; i++) { mSweep[i] = 0; } } else { for (int i = 0; i < humidity.length; i++) { mSweep[i] = humidity[i]; } } invalidate(); } }}
以上都是核心代码,并不是全部的代码,起他部分的代码就不贴出来了,感兴趣的朋友可以下载来研究研究。
转自:http://blog.csdn.net/a296777513/article/details/44564197
阅读全文
0 1
- Android自定义统计图(柱状图,折线图,饼状图)
- Android自定义统计图(柱状图,折线图,饼状图)
- Android自定义统计图(柱状图,折线图,饼状图)
- Android自定义统计图(柱状图,折线图,饼状图)
- Android自定义统计图(柱状图,折线图,饼状图)
- (转)Android自定义统计图(柱状图,折线图,饼状图)
- Android集成统计图 饼状图 折线图 和 柱状图
- Android集成统计图 饼状图 折线图 和 柱状图
- 自定义折线图/柱状图
- Android自定义View——折线统计图
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- 内核编译obj-m和obj-y的区别
- Python easyui的Layout
- Android使用友盟集成QQ、微信、微博等第三方登录
- 基于文本,优于轻量,用于交换数据——json解析(上篇)
- 对数据上传业务的一些总结
- Android自定义统计图(柱状图,折线图,饼状图)
- 数据结构--括号匹配检验
- cookie和session的区别
- C#编写串口程序(详细教程)
- 增强学习 比较好的入门文章
- 计算机网络中端到端与点到点的区别
- 在巨人的肩膀上(利用SDWebImage库再封装)
- Halcon一维运算相关算子整理
- js中以多个字符拆分字符串