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);
        }
    }

} 

這種動態的效果在模擬器上顯示會出現問題,真機正常. 

 

 






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM