欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

手把手教你用Android自定义饼状图

程序员文章站 2024-03-31 18:23:46
照例先上效果图 通过该例子,你能学到什么:      对paint 深入理解,画绘制饼图,矩形,文字等  &...

照例先上效果图

手把手教你用Android自定义饼状图

通过该例子,你能学到什么:

     对paint 深入理解,画绘制饼图,矩形,文字等

     加深对canvas的api的掌握,对自定义view掌握

下面我们分七步来完成一个简单的饼形图绘制过程。

1. 重新view的构造方法

public pieview(context context) {
 this(context, null);
 }

 public pieview(context context, attributeset attrs) {
 this(context, attrs, 0);
 }

 public pieview(context context, attributeset attrs, int defstyleattr) {
 super(context, attrs, defstyleattr);
 init();
 }

 private void init() {
 mpiecolorlist = new arraylist<>();
 mpievalue = new arraylist<>();
 mstringlist = new arraylist<>();
 mpaint = new paint();
 mmaxstring = "";
 mpaint.setcolor(color.black);
 mpaint.setstrokewidth(10);//画笔宽度
 mpaint.setantialias(true);//抗锯齿
 }

2.绘制图形

/**
 * 绘制饼图
 *
 * @param canvas
 * @param amount
 */
 private void drawpie(canvas canvas, int amount) {
 mpaint.setcolor(mcurrentcolor);
 mpaint.setstyle(paint.style.fill);
 int angle = (int) (360f * amount / mmaxvalue);
 log.d("angle", "drawpie: " + angle);
 canvas.drawarc(oval, mstartangle, angle, true, mpaint);
 mstartangle += angle;
 }

 /**
 * 绘制矩形
 *
 * @param canvas
 */
 private void drawrect(canvas canvas) {
 if (mcurrentindex == 0) {
  rect = new rectf(mrectmarginleft, mpadding, mrectmarginleft + rect_width, mpadding + rect_width);
  canvas.drawrect(rect, mpaint);
 } else {
  rect = new rectf(mrectmarginleft, (mcurrentindex) * text_vertical_padding + mpadding, mrectmarginleft + rect_width, (mcurrentindex) * text_vertical_padding + mpadding + rect_width);
  canvas.drawrect(rect, mpaint);
 }
 }

 /**
 * 绘画文字
 *
 * @param canvas
 * @param text
 */
 private void drawtext(canvas canvas, string text) {
 mpaint.setcolor(text_color);
 if (mcurrentindex == 0) {
  canvas.drawtext(text, mtextmarginleft, mpadding + text_size * 0.8f - 5, mpaint);
 } else {
  canvas.drawtext(text, mtextmarginleft, (mcurrentindex) * text_vertical_padding + mpadding + text_size * 0.8f - 5, mpaint);
 }
 }

3.pie 实体类

public class pie {
 public int piecolor;
 public int pievalue;
 public string piestring;

 public pie(int pievalue, string piestring, int piecolor) {
 this.pievalue = pievalue;
 this.piestring = piestring;
 this.piecolor = piecolor;
 }
}

4.xml引用

 <aikaifa.canvas.widget.pieview
 android:layout_width="match_parent"
 android:layout_height="200dp"
 android:id="@+id/pieview" />

5.填充数据

public class mainactivity extends activity {
 private arraylist<pie> piearraylist = new arraylist<>();
 private string[] arr = {"c#", "c", "c++", "java", "javascript", "object-c"};
 private int[] pre = {20, 30, 10, 10, 10, 20};
 private pieview pieview;

 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setcontentview(r.layout.activity_main);

 pieview = (pieview) findviewbyid(r.id.pieview);
 int[] piecolor = {getresources().getcolor(r.color.blue), getresources().getcolor(r.color.red), getresources().getcolor(r.color.gray_dark),
  getresources().getcolor(r.color.dark), getresources().getcolor(r.color.colorprimary), getresources().getcolor(r.color.black_alpha_light)};
 for (int i = 0; i < arr.length; i++) {
  pie pie = new pie(pre[i], arr[i], piecolor[i]);
  piearraylist.add(pie);
 }
 pieview.setpie(piearraylist);
 }

}

6.完整的pieview

public class pieview extends view {

 private paint mpaint;
 //饼图和矩形的距离
 private final int pie_rect_padding = getresources().getdimensionpixelsize(r.dimen.pie_rect_padding);
 //矩形的宽度
 private final int rect_width = getresources().getdimensionpixelsize(r.dimen.rect_width);
 //矩形和文字的距离
 private final int rect_text_padding = getresources().getdimensionpixelsize(r.dimen.rect_text_padding);
 //文字的大小
 private final int text_size = getresources().getdimensionpixelsize(r.dimen.text_size);
 //文字的垂直距离
 private final int text_vertical_padding = getresources().getdimensionpixelsize(r.dimen.text_vertical_padding);
 //得到文字颜色
 private final int text_color = getresources().getcolor(r.color.gray_dark);
 //文字和控件顶部的距离
 private float mpadding;
 //饼图的半径
 private int mpieradios;
 //所有数值的总和
 private int mmaxvalue;
 //饼图开始的角度
 private int mstartangle;
 //文字的宽度
 private int mtextwidth;
 //控件半高
 private int mcontrolhalfheight;
 //当前索引
 private int mcurrentindex;
 //左边距
 private int mrectmarginleft;
 private int mtextmarginleft;
 //当前颜色
 private int mcurrentcolor;
 //圆的范围
 private rectf oval;
 //最长的字符串
 private string mmaxstring;

 private list<integer> mpiecolorlist;
 private list<integer> mpievalue;
 private list<string> mstringlist;
 private arraylist<pie> mpiearraylist;

 private rectf rect;

 public pieview(context context) {
 this(context, null);
 }

 public pieview(context context, attributeset attrs) {
 this(context, attrs, 0);
 }

 public pieview(context context, attributeset attrs, int defstyleattr) {
 super(context, attrs, defstyleattr);
 init();
 }

 private void init() {
 mpiecolorlist = new arraylist<>();
 mpievalue = new arraylist<>();
 mstringlist = new arraylist<>();
 mpaint = new paint();
 mmaxstring = "";
 mpaint.setcolor(color.black);
 mpaint.setstrokewidth(10);//画笔宽度
 mpaint.setantialias(true);//抗锯齿
 }

 @override
 protected void onsizechanged(int width, int height, int oldwidth, int oldheight) {
 super.onsizechanged(width, height, oldwidth, oldheight);
 mtextwidth = (int) mpaint.measuretext(mmaxstring);
 mcontrolhalfheight = height / 2;
 //饼图半径
 mpieradios = mcontrolhalfheight - 5;
 //控件内容宽度
 int contentwidth = mpieradios * 2 + pie_rect_padding + rect_width + rect_text_padding + mtextwidth;
 //内容的左边距
 int contentmarginleft = (width - contentwidth) / 2;
 //矩形的左边距
 mrectmarginleft = contentmarginleft + mpieradios * 2 + pie_rect_padding;
 //文字的左边距
 mtextmarginleft = mrectmarginleft + rect_width + rect_text_padding;
 //文字和控件顶部的距离
 mpadding = height / mpiearraylist.size() * 0.8f;
 oval = new rectf(contentmarginleft, mcontrolhalfheight - mpieradios,
  contentmarginleft + mpieradios * 2, mcontrolhalfheight + mpieradios);
 }

 /**
 * @param piearraylist
 */
 public void setpie(arraylist<pie> piearraylist) {
 mpiearraylist = piearraylist;
 for (pie mpie : mpiearraylist) {
  mpiecolorlist.add(mpie.piecolor);
  mpievalue.add(mpie.pievalue);
  mstringlist.add(mpie.piestring);
  if (mmaxstring.length() > mpie.piestring.length())
  mmaxstring = mpie.piestring;
 }

 //使用postinvalidate可以直接在主线程中更新界面
 postinvalidate();
 }

 @override
 protected void ondraw(canvas canvas) {
 super.ondraw(canvas);

 mstartangle = -90;
 mcurrentindex = 0;
 mmaxvalue = 100;
 mpaint.setstyle(paint.style.fill);

 for (int i = 0; i < mpievalue.size(); i++) {
  mcurrentcolor = mpiecolorlist.get(mcurrentindex);
  log.i("mcurrentcolor", "ondraw: " + mcurrentcolor);
  drawpie(canvas, mpievalue.get(mcurrentindex));
  drawrect(canvas);
  drawtext(canvas, mstringlist.get(mcurrentindex));
  mcurrentindex++;
 }
 }

 /**
 * 绘制饼图
 *
 * @param canvas
 * @param amount
 */
 private void drawpie(canvas canvas, int amount) {
 mpaint.setcolor(mcurrentcolor);
 mpaint.setstyle(paint.style.fill);
 int angle = (int) (360f * amount / mmaxvalue);
 log.d("angle", "drawpie: " + angle);
 canvas.drawarc(oval, mstartangle, angle, true, mpaint);
 mstartangle += angle;
 }

 /**
 * 绘制矩形
 *
 * @param canvas
 */
 private void drawrect(canvas canvas) {
 if (mcurrentindex == 0) {
  rect = new rectf(mrectmarginleft, mpadding, mrectmarginleft + rect_width, mpadding + rect_width);
  canvas.drawrect(rect, mpaint);
 } else {
  rect = new rectf(mrectmarginleft, (mcurrentindex) * text_vertical_padding + mpadding, mrectmarginleft + rect_width, (mcurrentindex) * text_vertical_padding + mpadding + rect_width);
  canvas.drawrect(rect, mpaint);
 }
 }

 /**
 * 绘画文字
 *
 * @param canvas
 * @param text
 */
 private void drawtext(canvas canvas, string text) {
 mpaint.setcolor(text_color);
 if (mcurrentindex == 0) {
  canvas.drawtext(text, mtextmarginleft, mpadding + text_size * 0.8f - 5, mpaint);
 } else {
  canvas.drawtext(text, mtextmarginleft, (mcurrentindex) * text_vertical_padding + mpadding + text_size * 0.8f - 5, mpaint);
 }
 }

 @override
 public boolean ontouchevent(motionevent event) {
 if (event.getaction() == motionevent.action_down) {
  float x = event.getx();
  float y = event.gety();
  log.e("",x+"-----------");
 }
 return true;
 }
}

7.其他文件

colors.xml

  <color name="dark">#0097a7</color>
  <color name="grey">#e0e0e0</color>
  <color name="gray_dark">#666666</color>
  <color name="black_alpha_light">#3c3f41</color>
  <color name="black_light">#383838</color>
  <color name="blue">#03a9f4</color>
  <color name="red">#ff4081</color>

dimens.xml

  <dimen name="fab_margin">16dp</dimen>
  <dimen name="pie_rect_padding">30dp</dimen>
  <dimen name="rect_text_padding">6dp</dimen>
  <dimen name="rect_width">15dp</dimen>
  <dimen name="text_size">18sp</dimen>
  <dimen name="text_vertical_padding">25dp</dimen>

总结

好了,这样一个简单的饼形图绘制就算完成了。希望这篇文章的内容对各位android开发者们能有所帮助,如果有疑问大家可以留言交流。