Android自定义控件-折线图

时间:2021-09-25 22:28:22

好长时间没有更新博客了,终于可以抽出时间写点东西了,写点什么呢?最近在qq群里边有人问,下边的这个控件怎么画?如下图所示:图可以左右拖动,直到显示完全为止。刚开始看到这个效果图,我也想了一下总共分为以下几个步骤:

(1)坐标轴的绘画,并绘画坐标轴上的坐标值

(2)绘画坐标上的点,并将其串联起来

(3)最后进行封闭图形的填充

(4)事件的拖动重绘

Android自定义控件-折线图

1、首先定义自定义属性文件,并确定坐标轴的颜色,宽度,坐标文字的大小,线的颜色等

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="LineChart">
<attr name="xylinecolor" format="color" ></attr>
<attr name="xylinewidth" format="dimension"></attr>
<attr name="xytextcolor" format="color"></attr>
<attr name="xytextsize" format="dimension"></attr>
<attr name="linecolor" format="color"></attr>
<attr name="interval" format="dimension"></attr>
<attr name="bgcolor" format="color"></attr>
</declare-styleable> </resources>

2、主布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:ypm = "http://schemas.android.com/apk/res/com.ypm.linechartdemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.ypm.linechartdemo.LineChart
android:id="@+id/id_linechart"
android:layout_width="match_parent"
android:layout_height="match_parent"
ypm:xylinecolor="@color/xylinecolor"
ypm:xylinewidth="@dimen/xylinewidth"
ypm:xytextsize = "@dimen/xytextsize"
ypm:linecolor="@color/linecolor"
> </com.ypm.linechartdemo.LineChart> </RelativeLayout> 

3、接下来就是自定义LineChart控件,首先定义一些列的变量值如下:

/**
* 坐标轴的颜色
*/
private int xyColor; /**
* 坐标轴的宽度
*/
private int xyWidth; /**
* 坐标轴文字的颜色
*/
private int xyTextColor; /**
* 坐标轴文字的大小
*/
private int xyTextSize; /**
* 坐标轴的之间的间距
*/
private int interval; /**
* 折线的颜色
*/
private int lineColor; /**
* 背景颜色
*/
private int bgColor; /**
* 原点坐标最大x
*/
private int ori_x; /**
* 第一个点的坐标
*/
private int first_x; /**
* 第一个点的坐标最小x,和最大x坐标
*/
private int ori_min_x,ori_max_x; /**
* 原点坐标y
*/
private int ori_y; /**
* x的刻度值长度 默认值40
*/
private int xScale = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 80, getResources()
.getDisplayMetrics()); /**
* y的刻度值长度
*/
private int yScale = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 55, getResources()
.getDisplayMetrics()); /**
* x刻度
*/
private String[] xLabels; /**
* y刻度
*/
private String[] yLabels; /**
* x坐标轴中最远的坐标值
*/
private int maxX_X, maxX_Y; /**
* y坐标轴的最远坐标值
*/
private int minY_X, minY_Y; /**
* x轴最远的坐标轴
*/
private int x_last_x, x_last_y;
/**
* y轴最远的坐标值
*/
private int y_last_x, y_last_y; private double[] dataValues; /**
* 滑动时候,上次手指的x坐标
*/
private float startX;

4、读取属性文件上的值

public LineChart (Context context , AttributeSet attrs , int defStyle)
{
super(context, attrs, defStyle);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LineChart);
int count = array.getIndexCount();
for (int i = 0; i < count; i++)
{
int attr = array.getIndex(i);
switch (attr)
{
case R.styleable.LineChart_xylinecolor:
xyColor = array.getColor(attr, Color.GRAY); break; case R.styleable.LineChart_xylinewidth:
xyWidth = (int) array.getDimension(attr, 5);
break; case R.styleable.LineChart_xytextcolor: xyTextColor = array.getColor(attr, Color.BLACK);
break;
case R.styleable.LineChart_xytextsize:
xyTextSize = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
12, getResources().getDisplayMetrics()));
break; case R.styleable.LineChart_linecolor: lineColor = array.getColor(attr, Color.GRAY);
break; case R.styleable.LineChart_bgcolor:
bgColor = array.getColor(attr, Color.WHITE);
break; case R.styleable.LineChart_interval:
interval = (int) array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
100, getResources().getDisplayMetrics()));
break;
default:
break;
}
}
array.recycle();
}

 5、初始化相应的坐标值,在onMeasure中

主要进行原点,第一个点坐标,以及x最大值的相关的计算

     int width = getWidth();
int height = getHeight(); ori_x = 40;
ori_y = height - 40; maxX_X = width - 50;
minY_Y = 50; ori_min_x = width - 50 -40 - dataValues.length * xScale;
first_x = ori_x;
ori_max_x = first_x;

6、绘画坐标轴

 /**
*
* 功能描述:绘画坐标轴
*
* @param canvas
* @版本 1.0
* @创建者 ypm
* @创建时间 2015-8-24 上午10:39:59
* @版权所有
* @修改者 ypm
* @修改时间 2015-8-24 上午10:39:59 修改描述
*/
private void drawXYLine(Canvas canvas)
{
Paint paint = new Paint();
paint.setColor(xyColor);
paint.setAntiAlias(true);
paint.setStrokeWidth(xyWidth);
paint.setTextSize(xyTextSize);
// 绘画x轴
int max = first_x + (xLabels.length-1) * xScale + 50;
if (max > maxX_X)
{
max = getMeasuredWidth();
} x_last_x = max;
x_last_y = ori_y;
canvas.drawLine(first_x, ori_y, max, ori_y, paint);
// 绘画y轴
int min = ori_y - (yLabels.length - 1) * yScale - 50;
if (min < minY_Y)
{
min = minY_Y;
}
y_last_x = first_x;
y_last_y = min;
canvas.drawLine(first_x, ori_y, first_x, min, paint); // 绘画x轴的刻度
drawXLablePoints(canvas, paint);
// 绘画y轴的刻度
drawYLablePoints(canvas, paint); }

7、绘画折线图

这里运用到了多边形的绘画,通过Path进行绘画,并使用了多边形的填充,以及xfermode的相关知识,可以查相关的api进行了解


 private void drawDataLine(Canvas canvas)
{
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
// paint.setStyle(Paint.Style.FILL);
paint.setColor(xyColor);
Path path = new Path();
for (int i = 0; i < dataValues.length; i++)
{
int x = first_x + xScale * i;
if (i == 0)
{
path.moveTo(x, getYValue(dataValues[i]));
}
else
{
path.lineTo(x, getYValue(dataValues[i]));
}
canvas.drawCircle(x, getYValue(dataValues[i]), xyWidth, paint);
}
path.lineTo(first_x + xScale * (dataValues.length - 1), ori_y);
path.lineTo(first_x, ori_y);
path.close();
paint.setStrokeWidth(5);
// paint.setColor(Color.parseColor("#D7FFEE"));
paint.setColor(Color.parseColor("#A23400"));
paint.setAlpha(100);
// 画折线
canvas.drawPath(path, paint);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
canvas.clipPath(path); // 将折线超出x轴坐标的部分截取掉
paint.setStyle(Paint.Style.FILL);
paint.setColor(bgColor);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
RectF rectF = new RectF(0, 0, x_last_x, ori_y);
canvas.drawRect(rectF, paint);
} private float getYValue(double value)
{ return (float) (ori_y - value / 50 * yScale);
}

8、事件的拖动,重写onTouchEvent方法,

这里主要的逻辑就是:

(1)当手机的宽度小于坐标值的最大值的时候,就禁止拖动

(2)如果超过手机的宽度的时候,就通过裁剪功能将渲染的图像就行裁剪,拖动的时候,将没有显示的部分进行显示

主要分为3块:

第一块:第一个点的坐标+拖动的距离和第一点坐标的最大值进行比较

第二块:第一个点的坐标+拖动的距离和第一点坐标的最小值进行比较

第三块:是在第一,二块之间的

     @Override
public boolean onTouchEvent(MotionEvent event)
{
if ((dataValues.length * xScale + 50 + ori_x) < maxX_X- ori_x)
{
return false;
}
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN: startX = event.getX();
break;
case MotionEvent.ACTION_MOVE:
float distance = event.getX() - startX;
// Log.v("tagtag", "startX="+startX+",distance="+distance);
startX = event.getX();
if(first_x+distance > ori_max_x)
{
Log.v("tagtag", "111");
first_x = ori_max_x;
}
else if(first_x+distance<ori_min_x)
{
Log.v("tagtag", "222");
first_x = ori_min_x;
}
else
{
Log.v("tagtag", "333");
first_x = (int)(first_x + distance);
}
invalidate();
break;
}
return true;
}

9、最终效果图,如下

Android自定义控件-折线图

总结:

自定义控件的编写步骤可以分为以下几个步骤:

(1)编写attr.xml文件

(2)在layout布局文件中引用,同时引用命名空间

(3)在自定义控件中进行读取(构造方法拿到attr.xml文件值)

(4)覆写onMeasure()方法

(5)覆写onLayout(),onDraw()方法

具体用到哪几个方法,具体情况具体分析,关键点还是在算法上边。

参考文章:

http://blog.csdn.net/yifei1989/article/details/29891211

Android自定义控件-折线图

Android自定义控件-折线图的更多相关文章

  1. android绘画折线图二

    紧接着android绘画折线图一,下面来介绍第二种方法,使用该方法,首先需要一个Androidplot-core-0.4.3-release.jar,该jar包之后也包含在项目源码中 建立一个andr ...

  2. android绘画折线图一

    最近需要实现用android来画折线图,所以百度了一下,发现确实很多,也很乱,现在整理两种方法(第二种方法在[android绘画折线图二]中实现),仅供大家参考,一起学习研究. 第一种使用ChartF ...

  3. Android自定义折线图

    老师布置了个作业:http://www.cnblogs.com/qingxu/p/5316897.html 作业中提到的 “玩了几天以后,大家发现了一些很有意思的现象,比如黄金点在逐渐地往下移动.” ...

  4. android 自定义折线图

    看图: 比较简陋,主要是通过canvas画上去的: package com.example.democurvegraph.view; import java.util.ArrayList; impor ...

  5. Android自定义控件:图形报表的实现(折线图、曲线图、动态曲线图)(View与SurfaceView分别实现图表控件)

    图形报表很常用,因为展示数据比较直观,常见的形式有很多,如:折线图.柱形图.饼图.雷达图.股票图.还有一些3D效果的图表等. Android中也有不少第三方图表库,但是很难兼容各种各样的需求. 如果第 ...

  6. Android开发学习之路-自定义控件(天气趋势折线图)

    之前写了个天气APP,带4天预报和5天历史信息.所以想着要不要加一个折线图来显示一下天气变化趋势,难得有空,就写了一下,这里做些记录,脑袋不好使容易忘事. 先放一下效果: 控件内容比较简单,就是一个普 ...

  7. Android之自定义控件实现天气温度折线图和饼状图

    以前写了个天气的APP,最近把他更新了一个版本,就抽取其中的天气温度折现图这个功能写了这篇博客,来与大家分享,希望对你有所帮助. 效果如图: 代码: MainActivity.Java /**** * ...

  8. Android自定义控件 -Canvas绘制折线图&lpar;实现动态报表效果&rpar;

    有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas ...

  9. 最牛逼android上的图表库MpChart(二) 折线图

    最牛逼android上的图表库MpChart二 折线图 MpChart折线图介绍 MpChart折线图实例 MpChart效果 最牛逼android上的图表库MpChart(二) 折线图 最近工作中, ...

随机推荐

  1. JTree实现好友列表

    最近学习了一下JTree的使用方法: 先来看一下树的实例: 构建一个树, DefaultMutableTreeNode root = new DefaultMutableTreeNode(" ...

  2. jQuery超炫酷按钮插件及源码

    现在大部分网页的按钮都是经过美化的,那些原始的浏览器按钮太过于枯燥乏味,让用户失去和网站交互的兴趣.早期我们都是通过背景图片来美化网页按钮,而现在我们可以利用扩展性更好的CSS3来制作漂亮的网页按钮, ...

  3. paip&period;mysql备份慢的解决

    paip.mysql备份慢的解决.txt 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn.net/att ...

  4. &lbrack;翻译&rsqb;&lbrack;MVC 5 &plus; EF 6&rsqb; 7:加载相关数据

    原文:Reading Related Data with the Entity Framework in an ASP.NET MVC Application 1.延迟(Lazy)加载.预先(Eage ...

  5. 彻底理解Gradle的任务

    这是从我个人博客中复制过来的,没有重新进行排版,为了更好的阅读效果大家可以去我网站上阅读,地址:http://coolshell.info/blog/2015/07/gradle-tasks-guid ...

  6. js、jQuery 获取文档、窗口、元素的各种值

    基于两年开发经验,总结了 javascript.jQuery 获取窗口.文档.元素的各种值 javascript: 文档:是整个document所有的内容 浏览器当前窗口文档body的宽度: docu ...

  7. Spring MVC【入门】就这一篇!

    MVC 设计概述 在早期 Java Web 的开发中,统一把显示层.控制层.数据层的操作全部交给 JSP 或者 JavaBean 来进行处理,我们称之为 Model1: 出现的弊端: JSP 和 Ja ...

  8. MT【315】勾股数

    (高考压轴题)证明以下命题:(1)对任意正整数$a$都存在正整数$b,c(b<c)$,使得$a^2,b^2,c^2$成等差数列.(2)存在无穷多个互不相似的三角形$\Delta_n$,其边长$a ...

  9. mysql 开启慢查询

    linux启用MySQL慢查询 vim /etc/my.cnf [mysqld] slow-query-log = on slow_query_log_file = /var/log/slow_que ...

  10. 两类for循环

    九.两类for循环 (一)穷举 1.格式 for (初始条件;循环条件 ;循环改变) { for (初始条件;循环条件;循环改变) { for (初始条件;循环条件;循环改变) { if (判断条件) ...