Android开发自定义控件之折线图实现方法详解
本文实例讲述了android开发自定义控件之折线图实现方法。分享给大家供大家参考,具体如下:
前言
折线图是android开发中经常会碰到的效果,但由于涉及自定义view的知识,对许多刚入门的小白来说会觉得很高深。其实不然,接下来我就以尽量通俗的语言来说明下图折线图效果的实现过程。
效果图
实现过程
首先,选择自定义控件的方式。
自定义控件的实现有四种方式:
1.继承view,重写ondraw、onmeasure等方法。
2.继承已有的view(比如textview)。
3.继承viewgroup实现自定义布局。
4.继承已有的viewgroup(比如linearlayout)。
由于我们不需要多个控件进行组合,也不需要在原有控件基础上改造,故我们采用第1种方式即继承view来实现。代码如下,新建一个chartview类继承自view,并实现他的几个构造方法,并重写ondraw和onmeasure方法,因为我们要在ondraw方法里面进行绘制工作,并且我希望这个控件的长宽是相等的,所以在onmeasure方法设置宽高相等。设置长宽相等的方式很简单,我们不需要自己去测量实现,只需要调用父类的onmeasure方法,传参数(宽高值)时将都传入宽度(或者高度)即可。
public class chartview extends view { public chartview(context context) { super(context); } public chartview(context context, @nullable attributeset attrs) { super(context, attrs); } public chartview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, widthmeasurespec); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); } }
其次,绘制简单图形并显示出来。
在进行绘制之前,我们要进行若干初始化工作,其中就包括画笔的初始化。然后就可以进行绘制了,我们先绘制一个简单的圆圈,然后将控件放到布局文件中,运行看看效果。
chartview代码
public class chartview extends view { // 画笔 private paint paint; /** * 构造函数 */ public chartview(context context) { super(context); initwork(); } /** * 构造函数 */ public chartview(context context, @nullable attributeset attrs) { super(context, attrs); initwork(); } /** * 构造函数 */ public chartview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); initwork(); } /** * 初始化工作 */ private void initwork() { initpaint(); } /** * 画笔设置 */ private void initpaint() { paint = new paint(paint.anti_alias_flag); // 画笔样式为填充 paint.setstyle(paint.style.fill); // 颜色设为红色 paint.setcolor(color.red); // 宽度为3像素 paint.setstrokewidth(3); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, widthmeasurespec); } @override protected void ondraw(canvas canvas) { super.ondraw(canvas); // 画圆 canvas.drawcircle(300,300,100,paint); } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" <com.toprs.linechart.chartview android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.constraint.constraintlayout>
效果:
然后,绘制图表。
到目前为止,已经实现了最简单的一个自定义控件,虽然它什么功能都没有,只是简单显示一个红色圆圈,但本质都是一样的。接下来就开始图表的绘制。
1.初始化一些需要使用的值。
// 刻度之间的距离 private int degreespace;
@override protected void ondraw(canvas canvas) { super.ondraw(canvas); // 控件上下左右边界四至及控件的宽度(同时也是高度!) int left = getleft(); int right = getright(); int top = gettop(); int bottom = getbottom(); int w = getwidth(); // 图表距离控件边缘的距离 int graphpadding = w / 10; // 图表上下左右四至 int graphleft = left + graphpadding; int graphbottom = bottom - graphpadding; int graphright = right - graphpadding; int graphtop = top + graphpadding; // 图表宽度(也等同高度奥~) int graphw = graphright - graphleft; // 刻度之间的距离 degreespace = graphw / 8; }
2.灰色背景
// 背景 canvas.drawcolor(color.ltgray);
3.坐标系
// 画笔设置样式为stroke样式,即只划线不填充 paint.setstyle(paint.style.stroke); // 坐标系绘制 path pivotpath = new path(); //y轴 pivotpath.moveto(graphleft, graphbottom); pivotpath.lineto(graphleft, graphtop); //y轴箭头 pivotpath.lineto(graphleft - 12, graphtop + 20); pivotpath.moveto(graphleft, graphtop); pivotpath.lineto(graphleft + 12, graphtop + 20); //x轴 pivotpath.moveto(graphleft, graphbottom); pivotpath.lineto(graphright, graphbottom); //x轴箭头 pivotpath.lineto(graphright - 20, graphbottom + 12); pivotpath.moveto(graphright, graphbottom); pivotpath.lineto(graphright - 20, graphbottom - 12); canvas.drawpath(pivotpath, paint);
4.刻度虚线及数字
// y轴刻度虚线 for (int i = 1; i < 8; i++) { path ykedupath = new path(); // 线 paint.setcolor(color.white); paint.setstrokewidth(1); paint.setstyle(paint.style.stroke); paint.setpatheffect(new dashpatheffect(new float[]{5,5},0)); ykedupath.moveto(graphleft, graphbottom - i * degreespace); ykedupath.lineto(graphright, graphbottom - i * degreespace); canvas.drawpath(ykedupath, paint); // 数字 paint.setcolor(color.black); paint.setstyle(paint.style.fill); paint.settextsize(25); paint.setpatheffect(null); canvas.drawtext(i + "", graphpadding / 2, graphbottom - i * degreespace, paint); } // x轴刻度虚线 for (int i = 1; i < 8; i++) { path xkedupath = new path(); // 线 paint.setcolor(color.white); paint.setstyle(paint.style.stroke); paint.setstrokewidth(1); paint.setpatheffect(new dashpatheffect(new float[]{5,5},0)); xkedupath.moveto(graphleft + i * degreespace, graphbottom); xkedupath.lineto(graphleft + i * degreespace, graphtop); canvas.drawpath(xkedupath, paint); // 数字 paint.setcolor(color.black); paint.setstyle(paint.style.fill); paint.settextsize(25); paint.setpatheffect(null); canvas.drawtext(i + "", graphleft + i * degreespace, graphbottom + graphpadding / 2, paint); }
5.折线
在绘制折线之前,我们先要初始化几个参数。
// 模拟数据 private float[] data = {3.2f, 4.3f, 2.5f, 3.2f, 3.8f, 7.1f, 1.3f, 5.6f}; // 当前显示的数据数量 private int shownum=1;
// 折线 path linepath = new path(); for (int i = 0; i < shownum; i++) { int topointx = graphleft + i * degreespace; int topointy = graphbottom - ((int) (data[i] * degreespace)); paint.setcolor(color.yellow); paint.setstyle(paint.style.stroke); if (i==0){ linepath.moveto(topointx,topointy); }else { linepath.lineto(topointx, topointy); } // 节点圆圈 canvas.drawcircle(topointx, topointy,10,paint); paint.setcolor(color.white); paint.setstyle(paint.style.fill); canvas.drawcircle(topointx,topointy,7,paint); } paint.setcolor(color.yellow); paint.setstyle(paint.style.stroke); paint.setstrokewidth(3); canvas.drawpath(linepath, paint);
6.让图表动起来
为了实现数据依次显现的动画,我们开启一个线程是当前显示的数据数量即shownum变量不断加一,并间隔时间0.5秒。然后postinvalidate()重绘即可。
private void initwork() { initpaint(); // 开启线程,没隔0.5秒shownum加一 new thread(new runnable() { @override public void run() { while (true){ if (shownum<data.length){ shownum++; }else { shownum=1; } // 重绘 postinvalidate(); // 休眠0.5秒 try { thread.sleep(500); } catch (interruptedexception e) { e.printstacktrace(); } } } }).start(); }
好了,运行一下,便会实现上面的效果了。如果你觉得效果不够炫酷或者功能太少,那就自己完善吧~~
结语
由于自定义控件是android进阶路上必然要碰到的知识,所以希望大家重视。其实自定义控件说难也难说简单也简单。实现一些普通的效果还是很方便的,像这次举的例子,但如果要实现各种炫酷效果并且要完善各种功能的话,就需要各种知识的配合了,包括数学、物理、绘图等知识。所以还是需要平时不断积累的,看到别人的控件很棒的时候自己可以试着去实现一下,对自己的知识库不断进行补充,自然会娴熟的运用。本人也是菜鸟一枚,望共勉!!
上一篇: 昨天岳父老夫聊发少年狂
下一篇: 慈禧日常生活有多奢侈?吃个西瓜就很夸张了
推荐阅读
-
Android开发中方向传感器定义与用法详解【附指南针实现方法】
-
Android开发之ListView列表刷新和加载更多实现方法
-
Android开发之选项卡功能的实现方法示例
-
PHP7扩展开发之hello word实现方法详解
-
Android开发之PopupWindow创建弹窗、对话框的方法详解
-
Android开发之ViewFlipper自动播放图片功能实现方法示例
-
Android开发之动画实现方法
-
Android开发之自定义view实现通讯录列表A~Z字母提示效果【附demo源码下载】
-
Android开发实现ListView异步加载数据的方法详解
-
Android开发之HttpClient异步请求数据的方法详解【附demo源码下载】