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

代码:

public class MyView extends View {
    //坐标轴原点的位置
    private int xPoint=60;  
    private int yPoint=260;
    //刻度长度
    private int xScale=8;  //8个单位构成一个刻度
    private int yScale=40;
    //x与y坐标轴的长度
    private int xLength=380;
    private int yLength=240;
    
    private int MaxDataSize=xLength/xScale;   //横坐标  最多可绘制的点
    
    private List<Integer> data=new ArrayList<Integer>();   //存放 纵坐标 所描绘的点
    
    private String[] yLabel=new String[yLength/yScale];  //Y轴的刻度上显示字的集合
    
    
    private Handler mh=new Handler(){
        public void handleMessage(android.os.Message msg) {
            if(msg.what==0){                //判断接受消息类型
                MyView.this.invalidate();  //刷新View
            }
        };
    };
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        for (int i = 0; i <yLabel.length; i++) {
            yLabel[i]=(i+1)+"M/s";
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){     //在线程中不断往集合中增加数据
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(data.size()>MaxDataSize){  //判断集合的长度是否大于最大绘制长度
                        data.remove(0);  //删除头数据
                    }
                    data.add(new Random().nextInt(5)+1);  //生成1-6的随机数
                    mh.sendEmptyMessage(0);   //发送空消息通知刷新
                }
            }
        }).start();
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint=new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);  
        paint.setColor(Color.RED);
        //绘制Y轴
        canvas.drawLine(xPoint, yPoint-yLength, xPoint, yPoint, paint); 
        //绘制Y轴左右两边的箭头
        canvas.drawLine(xPoint, yPoint-yLength, xPoint-3,yPoint-yLength+6, paint);
        canvas.drawLine(xPoint, yPoint-yLength, xPoint+3,yPoint-yLength+6, paint);
        //Y轴上的刻度与文字
        for (int i = 0; i * yScale< yLength; i++) {
            canvas.drawLine(xPoint, yPoint-i*yScale, xPoint+5, yPoint-i*yScale, paint);  //刻度
            canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
        }
        //X轴
        canvas.drawLine(xPoint, yPoint, xPoint+xLength, yPoint, paint);
        //如果集合中有数据
        if(data.size()>1){
            for (int i = 1; i < data.size(); i++) {  //依次取出数据进行绘制
                canvas.drawLine(xPoint+(i-1)*xScale, yPoint-data.get(i-1)*yScale, xPoint+i*xScale, yPoint-data.get(i)*yScale, paint);
            }
        }
 
    }

}

上面绘制的折线使用的canvas.drawLine方法,还可以用canvas.drawPath方法实现.

        //实现的另一种方式
        if(data.size()>1){
            Path path=new Path();
            path.moveTo(xPoint, yPoint-data.get(0)*yScale);//起点
            for (int i = 1; i < data.size(); i++) {
                path.lineTo(xPoint+i*xScale, yPoint-data.get(i)*yScale);
            }
            canvas.drawPath(path, paint);

}

如果需求是这样的:

public class MyView extends View {
    //坐标轴原点的位置
    private int xPoint=60;  
    private int yPoint=260;
    //刻度长度
    private int xScale=8;  //8个单位构成一个刻度
    private int yScale=40;
    //x与y坐标轴的长度
    private int xLength=380;
    private int yLength=240;
    
    private int MaxDataSize=xLength/xScale;   //横坐标  最多可绘制的点
    
    private List<Integer> data=new ArrayList<Integer>();   //存放 纵坐标 所描绘的点
    
    private String[] yLabel=new String[yLength/yScale];  //Y轴的刻度上显示字的集合
    
    
    private Handler mh=new Handler(){
        public void handleMessage(android.os.Message msg) {
            if(msg.what==0){                //判断接受消息类型
                MyView.this.invalidate();  //刷新View
            }
        };
    };
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        for (int i = 0; i <yLabel.length; i++) {
            yLabel[i]=(i+1)+"M/s";
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){     //在线程中不断往集合中增加数据
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(data.size()>MaxDataSize){  //判断集合的长度是否大于最大绘制长度
                        data.remove(0);  //删除头数据
                    }
                    data.add(new Random().nextInt(5)+1);  //生成1-6的随机数
                    mh.sendEmptyMessage(0);   //发送空消息通知刷新
                }
            }
        }).start();
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint=new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);  
        paint.setColor(Color.RED);
        //绘制Y轴
        canvas.drawLine(xPoint, yPoint-yLength, xPoint, yPoint, paint); 
        //绘制Y轴左右两边的箭头
        canvas.drawLine(xPoint, yPoint-yLength, xPoint-3,yPoint-yLength+6, paint);
        canvas.drawLine(xPoint, yPoint-yLength, xPoint+3,yPoint-yLength+6, paint);
        //Y轴上的刻度与文字
        for (int i = 0; i * yScale< yLength; i++) {
            canvas.drawLine(xPoint, yPoint-i*yScale, xPoint+5, yPoint-i*yScale, paint);  //刻度
            canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
        }
        //X轴
        canvas.drawLine(xPoint, yPoint, xPoint+xLength, yPoint, paint);
        //实现填充
        paint.setStyle(Paint.Style.FILL);
        if(data.size()>1){
            Path path=new Path();
            path.moveTo(xPoint, yPoint);
            for (int i = 0; i < data.size(); i++) {
                path.lineTo(xPoint+i*xScale, yPoint-data.get(i)*yScale);
            }
            path.lineTo(xPoint+(data.size()-1)*xScale, yPoint);
            canvas.drawPath(path, paint);
        }
    }

}

如果还有这种需求:

public class MyView extends View {
    //坐标轴原点的位置
    private int xPoint=60;  
    private int yPoint=260;
    //刻度长度
    private int xScale=8;  //8个单位构成一个刻度
    private int yScale=40;
    //x与y坐标轴的长度
    private int xLength=380;
    private int yLength=240;
    
    private int MaxDataSize=xLength/xScale;   //横坐标  最多可绘制的点
    
    private List<Integer> data=new ArrayList<Integer>();   //存放 纵坐标 所描绘的点
    
    private String[] yLabel=new String[yLength/yScale];  //Y轴的刻度上显示字的集合
    
    
    private Handler mh=new Handler(){
        public void handleMessage(android.os.Message msg) {
            if(msg.what==0){                //判断接受消息类型
                MyView.this.invalidate();  //刷新View
            }
        };
    };
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        for (int i = 0; i <yLabel.length; i++) {
            yLabel[i]=(i+1)+"M/s";
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){     //在线程中不断往集合中增加数据
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(data.size()>MaxDataSize){  //判断集合的长度是否大于最大绘制长度
                        data.remove(0);  //删除头数据
                    }
                    data.add(new Random().nextInt(5)+1);  //生成1-6的随机数
                    mh.sendEmptyMessage(0);   //发送空消息通知刷新
                }
            }
        }).start();
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint=new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setAntiAlias(true);  
        paint.setColor(Color.RED);
        //绘制Y轴
        canvas.drawLine(xPoint, yPoint-yLength, xPoint, yPoint, paint); 
        //绘制Y轴左右两边的箭头
        canvas.drawLine(xPoint, yPoint-yLength, xPoint-3,yPoint-yLength+6, paint);
        canvas.drawLine(xPoint, yPoint-yLength, xPoint+3,yPoint-yLength+6, paint);
        //Y轴上的刻度与文字
        for (int i = 0; i * yScale< yLength; i++) {
            canvas.drawLine(xPoint, yPoint-i*yScale, xPoint+5, yPoint-i*yScale, paint);  //刻度
            canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
        }
        //X轴
        canvas.drawLine(xPoint, yPoint, xPoint+xLength, yPoint, paint);
        paint.setStrokeWidth(5);
        Paint paint2=new Paint();
        paint2.setColor(Color.BLACK);
        paint2.setStyle(Paint.Style.FILL);
        if(data.size()>1){
            Path path=new Path();
            Path path2=new Path();
            path.moveTo(xPoint, yPoint-data.get(0)*yScale);
            path2.moveTo(xPoint, yPoint);
            for (int i = 0; i < data.size(); i++) {
                path.lineTo(xPoint+i*xScale, yPoint-data.get(i)*yScale);
                path2.lineTo(xPoint+i*xScale, yPoint-data.get(i)*yScale);
            }
            path2.lineTo(xPoint+(data.size()-1)*xScale, yPoint);
            canvas.drawPath(path, paint);
            canvas.drawPath(path2, paint2);
        }
    }

}

这种动态的效果在模拟器上显示会出现问题,真机正常.

Android自定义控件 -Canvas绘制折线图(实现动态报表效果)的更多相关文章

  1. Android自己定义组件系列【9】——Canvas绘制折线图

    有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了非常多插件,可是非常多时候我们须要依据详细项目自己定义这些图表,这一篇文章我们一起来看看怎样在Android中使用Can ...

  2. Android自定义组件系列【9】——Canvas绘制折线图

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

  3. 用canvas绘制折线图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. canvas绘制折线图

    效果图: 重难点: 1.画布左上角的顶点的坐标为(0 ,0),右下角的坐标最大,与平常思维相反 2.数据的处理 html代码: <!DOCTYPE html><html lang=& ...

  5. canvas绘制折线图(仿echarts)

    遇到的问题:Retina屏上字体线条模糊问题 解决方案:放大canvas的大小,然后用css压缩回原大小,例如:想要900*400的画布,先将画布设置为 width="1800px" ...

  6. 【带着canvas去流浪】(2)绘制折线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 3.1 一般折线图 3.2 用贝塞尔曲线绘制平滑折线图 四. 大数据量场景 示例代码托管在:https://github.com/dashnowo ...

  7. 【Android开源框架】使用andbase开发框架实现绘制折线图

    在Android中,当有绘制折线图的需求时.大多数人使用的AChartEngine,来进行折线图的绘制.AChartEngine图表引擎确实能够实现折线图的功能.除此之外,我们还能够使用andbase ...

  8. 带着canvas去流浪系列之二 绘制折线图

    [摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  9. 【Canvas】(2)---绘制折线图

    绘制折线图 之前在工作的时候,用过百度的ECharts绘制折线图,上手很简单,这里通过canvas绘制一个简单的折线图.这里将一整个绘制过程分为几个步骤: 1.绘制网格 2.绘制坐标系 3.绘制点 4 ...

随机推荐

  1. 第47章 QR-Decoder-OV5640二维码识别—零死角玩转STM32-F429系列

    第47章     QR-Decoder-OV5640二维码识别 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.y ...

  2. NoClassDefFoundError: com/ibatis/sqlmap/engine/transaction/external/ExternalTransactionConfig处理

    根据老系统拷贝maven依赖新搭建了一个项目,启动抛异常如下: Caused by: java.lang.NoClassDefFoundError: com/ibatis/sqlmap/engine/ ...

  3. HDU 2047 EOF牛肉串

    水到不想整理,线性DP #include <algorithm> #include <iostream> #include <cstring> #include & ...

  4. 【模板时间】◆模板·I◆ 倍增计算LCA

    [模板·I]LCA(倍增版) 既然是一篇重点在于介绍.分析一个模板的Blog,作者将主要分析其原理,可能会比较无趣……(提供C++模板) 另外,给reader们介绍另外一篇非常不错的Blog(我就是从 ...

  5. mariadb源码编译安装及多实例

    准备文件源文件/app/mariadb-10.2.12.tar.gz cd /app/ tar xf mariadb-10.2.12.tar.gz cd  mariadb-10.2.12 mkdir ...

  6. spring-bean(xml方式管理)

    特点 每一次加载XML文件时候,都会将配置文件中包含的配置实例化. ID与name区别:name不是唯一的,但是可以使用特殊字符 Class:生成类的实例 Bean的作用域: 三种实例化方式 类的构造 ...

  7. PL/sql中如何声明变量,常量,控制语句及for,loop,while和顺序控制的使用

    pl/sql 什么是PL/SQL PL/SQL是结合oracle过程语言和机构化查询运行(SQL) 的一种扩展语言.使用PL/SQL可以编写具有很多高级功能的程序,有以下优点 PL/SOL可以采用过程 ...

  8. C指针(1)——指针在数组中的应用(程序讲解)

    2-1.c数组指针的定义: #include <stdio.h> int main() { char str[]="China Beijing Fujian"; //定 ...

  9. [Noip2016]愤怒的小鸟(状压DP)

    题目描述 题意大概就是坐标系上第一象限上有N只猪,每次可以构造一条经过原点且开口向下的抛物线,抛物线可能会经过某一或某些猪,求使所有猪被至少经过一次的抛物线最少数量. 原题中还有一个特殊指令M,对于正 ...

  10. 大话CNN经典模型:AlexNet

    2012年,Alex Krizhevsky.Ilya Sutskever在多伦多大学Geoff Hinton的实验室设计出了一个深层的卷积神经网络AlexNet,夺得了2012年ImageNet LS ...