1. 程式人生 > >android自定義折線圖——之簡單的溫度折線圖

android自定義折線圖——之簡單的溫度折線圖

              最近做了一個類似天氣預告的demo,其中有一個自定義折線圖,在網上找了很多例子,沒有一個合適的,於是只能參考別人的例子,根據自己的想法寫了一套demo.

           在做自定義控制元件之前,先熟悉一下paint和canvas的簡單使用。

              大概的思路無非就是先畫一個橫縱座標,然後根據點的X軸Y軸的座標,進行畫點畫線畫文字。

          最後的效果圖呢如下


          然後接下來看定義的折線圖控制元件了

<span style="color:#009900;">package com.yang.draw;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.Paint.Style;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;


class MyChartView extends View{
	
    public static final int RECT_SIZE = 10;      
    //列舉實現座標桌面的樣式風格
    public static enum Mstyle
    {
    	Line,Curve
    }

    private Mstyle mstyle=Mstyle.Line;
    private Point[] mPoints = new Point[100];  
      
    Context context;
    int bheight=0;
    HashMap<Double, Double> map;
    ArrayList<Double> dlk;
    int totalvalue=30;
    int pjvalue=5;
    String xstr,ystr="";//橫縱座標的屬性
    int margint=15;
    int marginb=40;
    int c=0;
    int resid=0;
    Boolean isylineshow;
   
    /**
    * 
    */
    public void SetTuView(HashMap<Double, Double> map,int totalvalue,int pjvalue,String xstr,String ystr,Boolean isylineshow) 
    {
        this.map=map;
        this.totalvalue=totalvalue;
        this.pjvalue=pjvalue;
        this.xstr=xstr;
        this.ystr=ystr;
        this.isylineshow=isylineshow;
   }  

    public MyChartView(Context ct)
    {
    	super(ct);
		this.context=ct;
    }
    
    public MyChartView(Context ct, AttributeSet attrs)
	{
		super( ct, attrs );
		this.context=ct;
	}
    
    public MyChartView(Context ct, AttributeSet attrs, int defStyle) 
	{		 
		super( ct, attrs, defStyle );
		this.context=ct;
	}
    
	@Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        if(c!=0)
        	this.setbg(c);
        if(resid!=0)
        	this.setBackgroundResource(resid);
        dlk=getintfrommap(map);
        int height=getHeight();
        if(bheight==0)
        	bheight=height-marginb;

        int width=getWidth();
        int blwidh=dip2px(context,50);
        int pjsize=totalvalue/pjvalue;//介面佈局的尺寸的比例
        // set up paint  
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);  
        paint.setColor(Color.GRAY);  
        paint.setStrokeWidth(1);  
        paint.setStyle(Style.STROKE);
        for(int i=0;i<pjsize+1;i++)//將頂點的線變為紅色的  警戒線
        {
        	if(i==pjsize)
        		paint.setColor(Color.RED);
        	canvas.drawLine(blwidh,bheight-(bheight/pjsize)*i+margint,width,bheight-(bheight/pjsize)*i+margint, paint);//Y座標
        	drawline(pjvalue*i+"°", blwidh/2, bheight-(bheight/pjsize)*i+margint, canvas);
        }
        ArrayList<Integer> xlist=new ArrayList<Integer>();//記錄每個x的值
        //畫直線(縱向)
        paint.setColor(Color.GRAY);
        if(dlk==null)
        	return;
        for(int i=0;i<dlk.size();i++)
        {
        	xlist.add(blwidh+(width-blwidh)/dlk.size()*i);
        	if(isylineshow)
        	{
        		canvas.drawLine(blwidh+(width-blwidh)/dlk.size()*i,margint,blwidh+(width-blwidh)/dlk.size()*i,bheight+margint, paint);
        	}
        	String day=null;
        	if(dlk.get(i)==1.0){
        		day="Mon";
        	}else if(dlk.get(i)==2.0){
        		day="Tue";
        	}else if(dlk.get(i)==3.0){
        		day="Wed";
        	}else if(dlk.get(i)==4.0){
        		day="Thu";
        	}else if(dlk.get(i)==5.0){
        		day="Fir";
        	}else if(dlk.get(i)==6.0){
        		day="Sat";
        	}else if(dlk.get(i)==7.0){
        		day="Sun";
        	}
        	drawline(day, blwidh+(width-blwidh)/dlk.size()*i, bheight+40, canvas);//X座標
        }

        //點的操作設定
        mPoints=getpoints(dlk, map, xlist, totalvalue, bheight);

        
        paint.setColor(Color.GREEN);  
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(0);
        
    	if(mstyle==Mstyle.Curve)
    		drawscrollline(mPoints, canvas, paint);
    	else
    		drawline(mPoints, canvas, paint);
    	
        paint.setColor(Color.RED);  
        paint.setStyle(Style.FILL);  
        for (int i=0; i<mPoints.length; i++)
        {  
        	
            canvas.drawRect(pointToRect(mPoints[i]),paint);
            //給點加上文字,也就是溫度,溫度其實就是map的values值。
            float indexty=(mPoints[i].y - RECT_SIZE/2+ mPoints[i].y + RECT_SIZE/2)/2;//y軸座標
            canvas.drawText(getValues(i+1.0)+"°", mPoints[i].x + RECT_SIZE/2+10, indexty, paint);
        }  
    }  

   
    private RectF pointToRect(Point p)
    {  
        return new RectF(p.x -RECT_SIZE/2, p.y - RECT_SIZE/2,p.x + RECT_SIZE/2, p.y + RECT_SIZE/2);             
    }  

    
    private void drawscrollline(Point[] ps,Canvas canvas,Paint paint)
    {
    	Point startp=new Point();
    	Point endp=new Point();
    	for(int i=0;i<ps.length-1;i++)
    	{
    		startp=ps[i];
    		endp=ps[i+1];
    		int wt=(startp.x+endp.x)/2;
        	Point p3=new Point();
        	Point p4=new Point();
        	p3.y=startp.y;
        	p3.x=wt;
        	p4.y=endp.y;
        	p4.x=wt;
        	
        	Path path = new Path();  
            path.moveTo(startp.x,startp.y); 
            path.cubicTo(p3.x, p3.y, p4.x, p4.y,endp.x, endp.y); 
            canvas.drawPath(path, paint);
    		
    	}
    }

    
    private void drawline(Point[] ps,Canvas canvas,Paint paint)
    {
    	Point startp=new Point();
    	Point endp=new Point();
    	for(int i=0;i<ps.length-1;i++)
    	{	
    	startp=ps[i];
    	endp=ps[i+1];
    	canvas.drawLine(startp.x,startp.y,endp.x,endp.y, paint);
    	}
    }
    
  
    private Point[] getpoints(ArrayList<Double> dlk,HashMap<Double, Double> map,ArrayList<Integer> xlist,int max,int h)
    {
    	Point[] points=new Point[dlk.size()];
    	for(int i=0;i<dlk.size();i++)
    	{
    		int ph=h-(int)(h*(map.get(dlk.get(i))/max));
    		
    		points[i]=new Point(xlist.get(i),ph+margint);
    	}
    	return points;
    }
    
   
    private void drawline(String text,int x,int y,Canvas canvas)
    {
    	Paint p = new Paint();
    	p.setAlpha(0x0000ff);   
    	p.setTextSize(20);   
    	String familyName = "宋體";   
    	Typeface font = Typeface.create(familyName,Typeface.BOLD);   
    	p.setTypeface(font);   
    	p.setTextAlign(Paint.Align.CENTER);     
    	canvas.drawText(text, x, y, p);
    }


    public  int dip2px(Context context, float dpValue) 
    {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
    
   
    public  int px2dip(Context context, float pxValue) 
    {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }
    //獲取map中的key鍵對應的values值
    private Double getValues(Double d){
    	Object obj = new Object();
    	obj = map.get(d);
    	
    	return (Double) obj;
    }
    //獲取map集合中key的值
    @SuppressWarnings("rawtypes")
	public ArrayList<Double> getintfrommap(HashMap<Double, Double> map)
    {
    	ArrayList<Double> dlk=new ArrayList<Double>();
    	int position=0;
    	if(map==null)
    		return null;
		Set set= map.entrySet();   
		Iterator iterator = set.iterator();
 
		 while(iterator.hasNext())
		{   
			@SuppressWarnings("rawtypes")
			Map.Entry mapentry  = (Map.Entry)iterator.next();  
			Double s=(Double)mapentry.getKey();
			dlk.add((Double)mapentry.getKey());//獲取map中的key值,獲取到的值是無序的
		} 
		 //對key值進行有序的排列,
		 for(int i=0;i<dlk.size();i++)
		 {
			 int j=i+1;  
	            position=i;  
	            Double temp=dlk.get(i);  
	            for(;j<dlk.size();j++)
	            {  
	            	if(dlk.get(j)<temp)
	            	{  
	            		temp=dlk.get(j);  
	            		position=j;  
	            	}  
	            }  
	            
	            dlk.set(position,dlk.get(i)); 
	            dlk.set(i,temp);  
		 }
		return dlk;
    	
    }

    
    
    
    public void setbg(int c)
    {
    	this.setBackgroundColor(c);
    }
    
	public HashMap<Double, Double> getMap() {
		return map;
	}

	public void setMap(HashMap<Double, Double> map) {
		this.map = map;
//		invalidate();//這裡進行重繪,如果在給map賦值之前執行了onDraw方法,則呼叫此方法,否則不需要。
	}

	public int getTotalvalue() {
		return totalvalue;
	}

	public void setTotalvalue(int totalvalue) {
		this.totalvalue = totalvalue;
	}

	public int getPjvalue() {
		return pjvalue;
	}

	public void setPjvalue(int pjvalue) {
		this.pjvalue = pjvalue;
	}

	public String getXstr() {
		return xstr;
	}

	public void setXstr(String xstr) {
		this.xstr = xstr;
	}

	public String getYstr() {
		return ystr;
	}

	public void setYstr(String ystr) {
		this.ystr = ystr;
	}

	public int getMargint() {
		return margint;
	}

	public void setMargint(int margint) {
		this.margint = margint;
	}

	public Boolean getIsylineshow() {
		return isylineshow;
	}

	public void setIsylineshow(Boolean isylineshow) {
		this.isylineshow = isylineshow;
	}

	public int getMarginb() {
		return marginb;
	}

	public void setMarginb(int marginb) {
		this.marginb = marginb;
	}

	public Mstyle getMstyle() {
		return mstyle;
	}

	public void setMstyle(Mstyle mstyle) {
		this.mstyle = mstyle;
	}

	public int getBheight() {
		return bheight;
	}

	public void setBheight(int bheight) {
		this.bheight = bheight;
	}

	public int getC() {
		return c;
	}

	public void setC(int c) {
		this.c = c;
	}

	public int getResid() {
		return resid;
	}

	public void setResid(int resid) {
		this.resid = resid;
	}
    
    
    
}  </span>
           程式碼中一些註釋都已經標註,大部分都是一些paint和canvas的用法了,參考連結的文章就可以。

       最後就是在主程式碼中給溫度賦值了

<span style="color:#009900;">package com.yang.draw;

import java.util.HashMap;
import java.util.Timer;

import com.yang.draw.MyChartView.Mstyle;
import com.yzxy.draw.R;

import android.os.Bundle;
import android.widget.Button;
import android.app.Activity;

public class MainActivity extends Activity {

	MyChartView tu;
	Button BT_Add;
	Timer mTimer =new Timer();
	HashMap<Double, Double> map;
	Double key=8.0;
	Double value=0.0;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		BT_Add=(Button)findViewById(R.id.bt_add);
		tu= (MyChartView)findViewById(R.id.menulist);
		tu.SetTuView(map,50,10,"x","y",false);
		map=new HashMap<Double, Double>();
		map.put(1.0, 13.0);
    	map.put(2.0, 25.0);
    	map.put(3.0, 32.0);
    	map.put(4.0, 31.0);
    	map.put(5.0, 16.0);
    	map.put(6.0, 36.0);
    	map.put(7.0, 26.0);
    	tu.setTotalvalue(50);
    	tu.setPjvalue(10);
    	tu.setMap(map);
		tu.setMargint(20);
		tu.setMarginb(50);
		tu.setMstyle(Mstyle.Line);
	
	}


}</span>
      其中大家要注意的是,我在給控制元件賦值時(tu.setMap(map)),onDraw方法還未執行,所以我將控制元件中的重繪方法invalidate()給注掉了,所以提醒大家,如果tu.setMap(map)執行比較靠後的話,在自定義控制元件中,給map賦值後加上重繪方法invalidate()。