zoukankan      html  css  js  c++  java
  • Android自定义控件 -Canvas绘制折线图(实现动态报表效果)

    有时候我们在项目中会遇到使用折线图等图形,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(xPointyPoint-yLengthxPointyPoint, paint); 
            //绘制Y轴左右两边的箭头
            canvas.drawLine(xPointyPoint-yLengthxPoint-3,yPoint-yLength+6, paint);
            canvas.drawLine(xPointyPoint-yLengthxPoint+3,yPoint-yLength+6, paint);
            //Y轴上的刻度与文字
            for (int i = 0; i * yScaleyLength; i++) {
                canvas.drawLine(xPointyPoint-i*yScalexPoint+5, yPoint-i*yScale, paint);  //刻度
                canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
            }
            //X轴
            canvas.drawLine(xPointyPointxPoint+xLengthyPoint, paint);
            //如果集合中有数据
            if(data.size()>1){
                for (int i = 1; i < data.size(); i++) {  //依次取出数据进行绘制
                    canvas.drawLine(xPoint+(i-1)*xScaleyPoint-data.get(i-1)*yScalexPoint+i*xScaleyPoint-data.get(i)*yScale, paint);
                }
            }
     
        }

    } 

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

            //实现的另一种方式
            if(data.size()>1){
                Path path=new Path();
                path.moveTo(xPointyPoint-data.get(0)*yScale);//起点
                for (int i = 1; i < data.size(); i++) {
                    path.lineTo(xPoint+i*xScaleyPoint-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(xPointyPoint-yLengthxPointyPoint, paint); 
            //绘制Y轴左右两边的箭头
            canvas.drawLine(xPointyPoint-yLengthxPoint-3,yPoint-yLength+6, paint);
            canvas.drawLine(xPointyPoint-yLengthxPoint+3,yPoint-yLength+6, paint);
            //Y轴上的刻度与文字
            for (int i = 0; i * yScaleyLength; i++) {
                canvas.drawLine(xPointyPoint-i*yScalexPoint+5, yPoint-i*yScale, paint);  //刻度
                canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
            }
            //X轴
            canvas.drawLine(xPointyPointxPoint+xLengthyPoint, paint);
            //实现填充
            paint.setStyle(Paint.Style.FILL);
            if(data.size()>1){
                Path path=new Path();
                path.moveTo(xPointyPoint);
                for (int i = 0; i < data.size(); i++) {
                    path.lineTo(xPoint+i*xScaleyPoint-data.get(i)*yScale);
                }
                path.lineTo(xPoint+(data.size()-1)*xScaleyPoint);
                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(xPointyPoint-yLengthxPointyPoint, paint); 
            //绘制Y轴左右两边的箭头
            canvas.drawLine(xPointyPoint-yLengthxPoint-3,yPoint-yLength+6, paint);
            canvas.drawLine(xPointyPoint-yLengthxPoint+3,yPoint-yLength+6, paint);
            //Y轴上的刻度与文字
            for (int i = 0; i * yScaleyLength; i++) {
                canvas.drawLine(xPointyPoint-i*yScalexPoint+5, yPoint-i*yScale, paint);  //刻度
                canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
            }
            //X轴
            canvas.drawLine(xPointyPointxPoint+xLengthyPoint, 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(xPointyPoint-data.get(0)*yScale);
                path2.moveTo(xPointyPoint);
                for (int i = 0; i < data.size(); i++) {
                    path.lineTo(xPoint+i*xScaleyPoint-data.get(i)*yScale);
                    path2.lineTo(xPoint+i*xScaleyPoint-data.get(i)*yScale);
                }
                path2.lineTo(xPoint+(data.size()-1)*xScaleyPoint);
                canvas.drawPath(path, paint);
                canvas.drawPath(path2, paint2);
            }
        }

    } 

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

     

     





    qq3061280@163.com
  • 相关阅读:
    NumPy
    NumPy切片和索引
    NumPy来自数值范围的数组
    NumPy来自现有数据的数组
    NumPy数组创建例程
    NumPy数组属性
    hdu 1072 Nightmare
    hdu 1010
    nyoj zb的生日
    Catch That Cow
  • 原文地址:https://www.cnblogs.com/aibuli/p/950c34f2bc0d02cbd290dd6a8339d42a.html
Copyright © 2011-2022 走看看