首页 > 代码库 > android自定义折线图

android自定义折线图

BrokenLine控件:

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.Shader;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup.LayoutParams;

import com.qianhua.healthy_brain.R;

/**
 * 线框图
 * 
 * @author Administrator
 * 
 */
public class BrokenLine extends View {

	private List<Integer> milliliter;
	private float tb;
	private float interval_left_right;
	private float interval_left;
	private float margin_bottom;
	private Paint paint_date, paint_brokenLine, paint_dottedline,
			paint_brokenline_big, framPanint;

	private int time_index;
	private Bitmap bitmap_point;
	private Path path;
	private float dotted_text;

	public float getDotted_text() {
		return dotted_text;
	}

	public void setDotted_text(float dotted_text) {
		this.dotted_text = dotted_text;
	}

	private int fineLineColor = 0x5faaaaaa; // 灰色
	private int blueLineColor = 0xff00ffff; // 蓝色
	private int orangeLineColor = 0xffd56f2b; // 橙色

	public BrokenLine(Context context, List<Integer> milliliter) {
		super(context);
		init(milliliter);
	}

	public void init(List<Integer> milliliter) {
		if (null == milliliter || milliliter.size() == 0)
			return;
		this.milliliter = delZero(milliliter);
		Resources res = getResources();
		tb = res.getDimension(R.dimen.historyscore_tb);
		interval_left_right = tb * 5.0f;
		interval_left = tb * 0.5f;
		margin_bottom=8*tb * 0.2f;

		paint_date = new Paint();
		paint_date.setStrokeWidth(tb * 0.1f);
		paint_date.setTextSize(tb * 1.2f);
		paint_date.setColor(fineLineColor);

		paint_brokenLine = new Paint();
		paint_brokenLine.setStrokeWidth(tb * 0.1f);
		paint_brokenLine.setColor(blueLineColor);
		paint_brokenLine.setAntiAlias(true);

		paint_dottedline = new Paint();
		paint_dottedline.setStyle(Paint.Style.STROKE);
		paint_dottedline.setColor(fineLineColor);

		paint_brokenline_big = new Paint();
		paint_brokenline_big.setStrokeWidth(tb * 0.2f);
		paint_brokenline_big.setColor(fineLineColor);
		paint_brokenline_big.setAntiAlias(true);

		framPanint = new Paint();
		framPanint.setAntiAlias(true);
		framPanint.setStrokeWidth(2f);

		path = new Path();
		bitmap_point = BitmapFactory.decodeResource(getResources(),
				R.drawable.icon_point_blue);
		setLayoutParams(new LayoutParams(
				(int) (this.milliliter.size() * interval_left_right),
				LayoutParams.MATCH_PARENT));
	}

	/**
	 * 移除左右为零的数据
	 * 
	 * @return
	 */
	public List<Integer> delZero(List<Integer> milliliter) {
		List<Integer> list = new ArrayList<Integer>();
		int sta = 0;
		int end = 0;
		for (int i = 0; i < milliliter.size(); i++) {
			if (milliliter.get(i) != 0) {
				sta = i;
				break;
			}
		}
		for (int i = milliliter.size() - 1; i >= 0; i--) {
			if (milliliter.get(i) != 0) {
				end = i;
				break;
			}
		}
		for (int i = 0; i < milliliter.size(); i++) {
			if (i >= sta && i <= end) {
				list.add(milliliter.get(i));
			}
		}
		time_index = sta;
//		dotted_text = ((Collections.max(milliliter) - Collections .min(milliliter)) / 12.0f * 5.0f);
		return list;
	}

	protected void onDraw(Canvas c) {
		if (null == milliliter || milliliter.size() == 0)
			return;
		drawStraightLine(c);
		drawBrokenLine(c);
		drawDate(c);
	}

	/**
	 * 绘制竖线
	 * 
	 * @param c
	 */
	public void drawStraightLine(Canvas c) {
		
		int count_line = 0;
		for (int i = 0; i < milliliter.size(); i++) {
			if (i==0) {//绘制Y轴
				c.drawLine(interval_left_right * i, 0, interval_left_right * i, getHeight() - margin_bottom, paint_date);
				for (int j = 0; j <10; j++) {
					c.drawText(String.valueOf(10*(j+1)), 0 ,(getHeight()-margin_bottom)/10*(10-(j+1)), paint_date);
					if (j==5){//绘制虚线
						paint_dottedline.setColor(orangeLineColor);
						Path path = new Path();
						path.moveTo(0, (getHeight()-margin_bottom)/10*(10-(j+1)));
						path.lineTo(getWidth(), (getHeight()-margin_bottom)/10*(10-(j+1)));
						PathEffect effects = new DashPathEffect(new float[] { tb * 0.3f,
								tb * 0.3f, tb * 0.3f, tb * 0.3f }, tb * 0.1f);
						paint_dottedline.setPathEffect(effects);
						c.drawPath(path, paint_dottedline);
					} 					
					
				}
				continue;
			}
			//绘制竖线 连续四条为一组
			paint_dottedline.setColor(fineLineColor);
			if (count_line == 0) {
				c.drawLine(interval_left_right * i, 0, interval_left_right * i, getHeight() - margin_bottom, paint_date);
			}
			if (count_line == 2) {
				c.drawLine(interval_left_right * i, tb * 1.5f, interval_left_right * i, getHeight() - margin_bottom, paint_date);
			}
			if (count_line == 1 || count_line == 3) {
				Path path = new Path();
				path.moveTo(interval_left_right * i, tb * 1.5f);
				path.lineTo(interval_left_right * i, getHeight() - margin_bottom);
				PathEffect effects = new DashPathEffect(new float[] { tb * 0.3f, tb * 0.3f, tb * 0.3f, tb * 0.3f }, tb * 0.1f);
				paint_dottedline.setPathEffect(effects);
				c.drawPath(path, paint_dottedline);
			}
			count_line++;
			if (count_line >= 4) {
				count_line = 0;
			}
		}
		//绘制X轴
		c.drawLine(0, getHeight() - margin_bottom, getWidth(), getHeight() - margin_bottom, paint_brokenline_big);
	}

	/**
	 * 绘制折线
	 * 
	 * @param c
	 */
	public void drawBrokenLine(Canvas c) {
		int index = 0;
		float temp_x = 0;
		float temp_y = 0;
//		float base = (getHeight() - tb * 3.0f) / (Collections.max(milliliter) - Collections.min(milliliter));
		float base = (getHeight() - margin_bottom) / 100;

		Shader mShader = new LinearGradient(0, 0, 0, getHeight(), new int[] {
				Color.argb(100, 0, 255, 255), Color.argb(45, 0, 255, 255),
				Color.argb(10, 0, 255, 255) }, null, Shader.TileMode.CLAMP);
		framPanint.setShader(mShader);

		for (int i = 0; i < milliliter.size() - 1; i++) {
			Log.e("i", ""+milliliter.get(i));
			float x1 = interval_left_right * i;
			float y1 =  getHeight() - margin_bottom - (base * milliliter.get(i));
			float Y1 =  milliliter.get(i);
			float x2 = interval_left_right * (i + 1);
			float y2 =  getHeight() - margin_bottom - (base * milliliter.get(i + 1));
			float Y2 =  milliliter.get(i+1);

			if ((int) (base * milliliter.get(i + 1)) == 0 && index == 0) {
				index++;
				temp_x = x1;
				temp_y = y1;
			}
			if ((int) (base * milliliter.get(i + 1)) != 0 && index != 0) {
				index = 0;
				x1 = temp_x;
				y1 = temp_y;
			}
			
			paint_date.setColor(orangeLineColor);
			if (i==0) c.drawText(String.valueOf(Y1), x1, y1, paint_date);//绘出第一个值的大小
			
			if (index == 0) {
				c.drawText(String.valueOf(Y2), x2, y2, paint_date);//绘出第i+1个值的大小
				c.drawLine(x1, y1, x2, y2, paint_brokenLine);
				path.lineTo(x1, y1);
				if (i != 0)
					c.drawBitmap(bitmap_point,
							x1 - bitmap_point.getWidth() / 2,
							y1 - bitmap_point.getHeight() / 2, null);
				if (i == milliliter.size() - 2) {
					path.lineTo(x2, y2);
					path.lineTo(x2, getHeight());
					path.lineTo(0, getHeight());
					path.close();
					c.drawPath(path, framPanint);
					c.drawBitmap(bitmap_point,
							x2 - bitmap_point.getWidth() / 2,
							y2 - bitmap_point.getHeight() / 2, null);
				}
			}
		}
		paint_date.setColor(fineLineColor);

	}

	/**
	 * 绘制时间
	 * 
	 * @param c
	 */
	public void drawDate(Canvas c) {
		
		Date date=new Date();//取时间 
		Calendar calendar =new  GregorianCalendar(); 
		calendar.setTime(date); 
		SimpleDateFormat dateFormat=new SimpleDateFormat("MM-dd");
		String[] dates=new String[milliliter.size()];
		for (int i = 0; i < milliliter.size(); i++) {
		     calendar.add(calendar.DATE,1);//把日期往后增加一天.整数往后推,负数往前移动 
		     date=calendar.getTime();   //这个时间就是日期往后推一天的结果 
		     dates[i]=dateFormat.format(date).toString();
		}
		
		for (int i = 0; i < milliliter.size(); i += 1) {
			paint_date.setStrokeWidth(tb * 2.8f);
			c.drawText(dates[i], interval_left_right * i ,getHeight(), paint_date);
		}

	}
}

Activity:

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.RelativeLayout;

import com.qianhua.healthy_brain.R;
import com.qianhua.healthy_brain.widget.BrokenLine;

public class TrainResultActivity extends Activity {
	RelativeLayout linear;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.train_result);
		List<Integer> lists = new ArrayList<Integer>();//线性图  范围0-100
		for (int i = 0; i < 48; i++) {
			if (i < 8 || i == 28 || i == 12 || i == 18 || i == 20 || i == 30
					|| i == 34) {
				lists.add(0);
			} else {
//				int item=getRandom(0, 100);
//				Log.w(""+i, ""+item);
				lists.add(getRandom(0, 100));
			}
		}
		linear= (RelativeLayout) findViewById(R.id.linear);
		linear.addView(new BrokenLine(this,lists));
	}

	public int getRandom(int min,int max){
		return (int) Math.round(Math.random()*(max-min)+min);
	}
}


xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f4f4f7"
        android:orientation="vertical" >

        <HorizontalScrollView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_margin="10dp"
            android:scrollbars="none" >

            <RelativeLayout
                android:id="@+id/linear"
                android:layout_marginTop="30dp"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" >
            </RelativeLayout>
        </HorizontalScrollView>
    </LinearLayout>

</LinearLayout>

参考:http://www.apkbus.com/forum.php?mod=viewthread&tid=158365&extra=page%3D1

android自定义折线图