手把手教你用Android自定义饼状图
程序员文章站
2024-03-05 16:31:31
照例先上效果图
通过该例子,你能学到什么:
对paint 深入理解,画绘制饼图,矩形,文字等
&...
照例先上效果图
通过该例子,你能学到什么:
对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开发者们能有所帮助,如果有疑问大家可以留言交流。