您的位置:首页 > 其它

自定义控件-精美的心电图

2016-12-11 23:16 316 查看
大家好,最近项目上要优化一些Ui,发下之前的一些界面不太美观,比如说关于心电的一些折线图展示等问题。于是就乘着一些空余时间谢了个心电图的控件。来与大家一起分享。

由于需要根据实际情况设置不同的目标线会有不同的情况。

 有一个目标线的效果图:



/**
* 设置目标值1
*
* @param goal
*/
public void setGoal_one(int goal) {
this.goal = goal;
maxValue = getListOgMax(y_array);
minValus = getListOgMin(y_array);
if (goal > maxValue) {
maxValue = goal;
}
if (goal < minValus) {
minValus = goal;
}
drawFullDistance = maxValue - minValus;//最大值-最小值
perunit_valus = drawFullDistance / UNIT_NUM;
postInvalidate();
}




 有两个目标线的效果图:

/**
* 设置目标值
*
* @param goal_min,goal_max
*/
public void setMyGoadToLine(int goal_min, int goal_max) {
this.goal_min = goal_min;
this.goal_max = goal_max;

maxValue = getListOgMax(y_array);
maxValue = Math.max(maxValue, goal_max);

minValus = getListOgMin(y_array);
minValus = Math.min(minValus, goal_min);

drawFullDistance = maxValue - minValus;//最大值-最小值
perunit_valus = drawFullDistance / UNIT_NUM;
postInvalidate();
}




对与自定义组件比较陌生童鞋们可以访问我之前的一些博客:

http://blog.csdn.net/androidstarjack/article/list/5

接下来主要是绘制一些主要关键点:

1.绘制底部的日期 

/**
* 绘制底部的日期
*
* @param canvas
*/
private void drawBottomDateTypeText(Canvas canvas) {
if (xValues == null) {
return;
}
canvas.translate(0, myHeightCell);
// canvas.drawRect(0,0,getMeasuredWidth() * 1F,perUnitCell * 2f,paint_date);
for (int i = 0; i < xValues.size(); i++) {
float centerD = perBottomTextLehght * i + perBottomTextLehght;
String text = Utils.date2String(Long.parseLong(xValues.get(i)), "MM月dd日");
float textLength = paint_date.measureText(text) / 2;
float startX = centerD - textLength;
//float startY = perUnitCell * 2;
Rect rectf = new Rect();
paint_date.getTextBounds(text, 0, text.length(), rectf);
float startY = perUnitCellHeifht * 2 - rectf.height() / 2;
canvas.drawText(text, startX, startY, paint_date);
}
}
 2. 绘制单元格

/**
* 绘制单元格
*
* @param canvas
*/
private void drawUniteCell(Canvas canvas) {

for (int i = 0; i < myHeightCell / perUnitCellHeifht; i++) {
float startX = 0;
float startY = i * perUnitCellHeifht;
float endX = getMeasuredWidth();
float endY = i * perUnitCellHeifht;
canvas.drawLine(startX, startY, endX, endY, framPanint);
}

for (int i = 0; i < getMeasuredWidth() / perUnitCellHeifht; i++) {
float startX = i * perUnitCellHeifht;
float startY = 0;
float endX = i * perUnitCellHeifht;
float endY = myHeightCell;
canvas.drawLine(startX, startY, endX, endY, framPanint);
}
}


3.绘制目标线

/**
* 绘制目标线
*
* @param canvas
*/
private void drawGoalLine(Canvas canvas) {
canvas.save();
if (goal_min > 0) {
float getCurrenY = (goal_min - minValus) / perunit_valus * perUnitCellHeifht;
float startX1 = 0;
float startY1 = (getCurrenY == 0 ? (10) : getCurrenY);
float endX1 = currentWidth - 2;
float endY1 = startY1;
canvas.drawLine(startX1, -startY1, endX1, -endY1, paint_gold1);
String resultGroal = "目标:" + goal_min;
canvas.drawText(resultGroal, startX1 + getDrawMyBottomTextDefaultPadding(resultGroal, paint_date), -startY1 - 10, paint_date);
LogUtil.e("yuyahao", "goal_min:  " + goal_min + "          " + startX1 + "         -" + startY1 + "      " + endX1 + "      -" + endY1);
}
if (goal_max > 0) {
float getCurrenY = (goal_max - minValus) / perunit_valus * perUnitCellHeifht;
float startX2 = 0;
float startY2 = (getCurrenY == 0 ? (10) : getCurrenY);
;
float endX2 = currentWidth - 2;
float endY2 = startY2;
canvas.drawLine(startX2, -startY2, endX2, -endY2, paint_gold1);
String resultGroal = "目标:" + goal_max;
canvas.drawText(resultGroal, startX2 + getDrawMyBottomTextDefaultPadding(resultGroal, paint_date), -startY2 - 10, paint_date);
LogUtil.e("yuyahao", "goal_max:  " + goal_max + "          " + startX2 + "         -" + startY2 + "      " + endX2 + "      -" + endY2);
}
if (goal > 0) {
float getCurrenY = (goal - minValus) / perunit_valus * perUnitCellHeifht;
float startX = 0;
float startY = (getCurrenY == 0 ? (10) : getCurrenY);
float endX = currentWidth - 2;
float endY = startY;
canvas.drawLine(startX, -startY, endX, -endY, paint_gold1);
String resultGroal = "目标:" + goal;
canvas.drawText("目标:" + goal, startX + getDrawMyBottomTextDefaultPadding(resultGroal, paint_date), -startY - 10, paint_date);
LogUtil.e("yuyahao", "goal:  " + goal + "          " + startX + "         -" + startY + "      " + endX + "      -" + endY);
}
}


4,.设置目标线

  /**
* 设置目标值
*
* @param goal_min,goal_max
*/
public void setMyGoadToLine(int goal_min, int goal_max) {
this.goal_min = goal_min;
this.goal_max = goal_max;

maxValue = getListOgMax(y_array);
maxValue = Math.max(maxValue, goal_max);

minValus = getListOgMin(y_array);
minValus = Math.min(minValus, goal_min);

drawFullDistance = maxValue - minValus;//最大值-最小值
perunit_valus = drawFullDistance / UNIT_NUM;
postInvalidate();
}


最重要的还是每次更新完毕后要精确计算其:目标线和集合中的最大值和最小值:

maxValue = getListOgMax(y_array);
maxValue = Math.max(maxValue, goal_max);

minValus = getListOgMin(y_array);
minValus = Math.min(minValus, goal_min);

if (goal > 0) {
if (goal > maxValue) {
maxValue = goal;
}
if (goal < minValus) {
minValus = goal;
}
}
drawFullDistance = maxValue - minValus;//最大值-最小值
perunit_valus = drawFullDistance / UNIT_NUM;


好,最后附上源码:

package com.example.administrator.myapplication.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.view.ViewTreeObserver;

import com.example.administrator.myapplication.R;
import com.example.administrator.myapplication.utils.DensityUtil;
import com.example.administrator.myapplication.utils.LogUtil;
import com.example.administrator.myapplication.utils.Utils;

import java.util.Collections;
import java.util.List;

/**
* 折线图
*
* @author yuyahao
*/

public class MyBrokenLineView extends View {
/*********
* 最大值和最小值
*********/
private Context context;
private int MARGIN_VALUE = 0;//margin值为10
private Paint paint_date;//绘制底部日期
private Paint paint_brokenLine;//绘制底部的一根线
private Paint paint_dot;//绘制圆点的一根线
private Paint paint_gold1;//目标线
private Paint framPanint;//绘制单元格
private Paint paintBg;
private int perUnitCellHeifht = 10;
private float tb;
private List<String> xValues;//底部日期
private List<Float> y_array;//y轴坐标的值
private final int MAX_SHOW_TEXT = 6;//一屏幕上最多显示的日期的个数
private int perBottomTextLehght = 0;//每个单元格的高度
private int myHeightCell = 0;//单元格所在总高度
private float maxValue = 0, minValus = 0;//y轴方向上的最大值和最小值
private float drawFullDistance;//最大值-最小值
private float perunit_valus = 0;
private int currentWidth;
private int UNIT_NUM;
private Path path;
private boolean isDrawRectBackgrodund = false;//是否绘制底部的背景小方格
private int goal_min;//设置目标值1(2个goal的目标范围的最小值)
private int goal_max;//设置目标值2
private int goal;//设置目标值2
private boolean isDrawRectBackgrodundColor = false;

/*public MyBrokenLineView(Context context) {
super(context);
this.context = context;
}*/
public MyBrokenLineView(Context context, List<String> xValues, List<Float> y_array) {
super(context);
this.context = context;
this.xValues = xValues;
this.y_array = y_array;
initData();
initDefaltData();
}

public MyBrokenLineView(Context context, List<String> xValues, List<Float> y_array, int goal_min, int goal_max) {
super(context);
this.context = context;
this.xValues = xValues;
this.y_array = y_array;
this.goal_min = goal_min;
this.goal_max = goal_max;
initData();
initDefaltData();
}

public MyBrokenLineView(Context context, List<String> xValues, List<Float> y_array, int goal) {
super(context);
this.context = context;
this.xValues = xValues;
this.y_array = y_array;
this.goal = goal;
initData();
initDefaltData();
}

private void initDefaltData() {
perBottomTextLehght = DensityUtil.getScreenIntWidth(context) / MAX_SHOW_TEXT;
if (xValues != null) {
currentWidth = xValues.size() * perBottomTextLehght;
}
/* maxValue = getListOgMax(y_array);
minValus = getListOgMin(y_array);
drawFullDistance = maxValue - minValus;//最大值-最小值*/

maxValue = getListOgMax(y_array);
maxValue = Math.max(maxValue, goal_max);

minValus = getListOgMin(y_array);
minValus = Math.min(minValus, goal_min);

if (goal > 0) {
if (goal > maxValue) {
maxValue = goal;
}
if (goal < minValus) {
minValus = goal;
}
}
drawFullDistance = maxValue - minValus;//最大值-最小值
perunit_valus = drawFullDistance / UNIT_NUM;

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(widthMeasureSpec);

int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY) {
currentWidth = widthSize;
if (currentWidth < widthMeasureSpec) {
currentWidth = DensityUtil.getScreenIntWidth(context);
}
} else {
if (currentWidth < DensityUtil.getScreenIntWidth(context)) {
currentWidth = DensityUtil.getScreenIntWidth(context);
}
}
if (heightMode == MeasureSpec.EXACTLY) {
heightMeasureSpec = heightSize;
} else {
heightMeasureSpec = DensityUtil.dip2px(context, 200);
}
currentWidth = currentWidth - DensityUtil.dip2px(context, 10);//出去左右填充后padding
setMeasuredDimension(currentWidth, heightMeasureSpec);
myHeightCell = heightMeasureSpec - perUnitCellHeifht * 4;
UNIT_NUM = myHeightCell / perUnitCellHeifht;//竖向一共有几个单元格
perunit_valus = drawFullDistance / UNIT_NUM;
}

private void initData() {
tb = context.getResources().getDimension(R.dimen.historyscore_tb);
paint_date = new Paint();
paint_date.setStrokeWidth(tb * 0.1f);
paint_date.setTextSize(tb * 1f);
paint_date.setAntiAlias(true);
paint_date.setTextAlign(Paint.Align.CENTER);
paint_date.setColor(ContextCompat.getColor(context, R.color.black));

paint_brokenLine = new Paint();
paint_brokenLine.setAntiAlias(true);
paint_brokenLine.setStrokeWidth(tb * 0.1f);
paint_brokenLine.setColor(ContextCompat.getColor(context, R.color.theme_color));
paint_brokenLine.setStyle(Paint.Style.STROKE);

paint_dot = new Paint();
paint_dot.setAntiAlias(true);
paint_dot.setStrokeWidth(tb * 0.1f);
paint_dot.setColor(ContextCompat.getColor(context, R.color.theme_color));
paint_dot.setStyle(Paint.Style.FILL);

paint_gold1 = new Paint();
paint_gold1.setAntiAlias(true);
paint_gold1.setStrokeWidth(tb * 0.1f);
paint_gold1.setColor(ContextCompat.getColor(context, R.color.titlebar_bg_color));
paint_gold1.setStyle(Paint.Style.STROKE);

framPanint = new Paint();
framPanint.setAntiAlias(true);
framPanint.setStrokeWidth(tb * 0.1f);
framPanint.setColor(ContextCompat.getColor(context, R.color.black));
framPanint.setStyle(Paint.Style.FILL);
framPanint.setAlpha(40);

paintBg = new Paint();
paintBg.setAntiAlias(true);
paintBg.setColor(ContextCompat.getColor(context, R.color.black4));

perUnitCellHeifht = DensityUtil.dip2px(context, 10);
path = new Path();
MARGIN_VALUE = DensityUtil.dip2px(context, 10);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(0, MARGIN_VALUE * 2);
if (isDrawRectBackgrodundColor) {//绘制背景颜色
canvas.drawColor(paintBg.getColor());
}

if (isDrawRectBackgrodund) {//绘制底部单元格
drawUniteCell(canvas);
}
canvas.save();
if (xValues == null || xValues.size() == 0) {
return;
}
//绘制底部文字
drawBottomDateTypeText(canvas);
//绘制目标线
drawGoalLine(canvas);
//绘制 描点绘制折线图
drawPointAndLine(canvas);
}

/**
* 绘制 描点绘制折线图
*
* @param canvas
*/
private void drawPointAndLine(Canvas canvas) {
if (y_array == null || y_array.size() == 0) {
return;
}
canvas.save();
//canvas.drawLine(0,0,getMeasuredWidth(),5,paint_date);
for (int i = 0; i < y_array.size(); i++) {
float yalue = y_array.get(i);
float cx = perBottomTextLehght * i + perBottomTextLehght / 2 + perUnitCellHeifht / 2;
float cy = (yalue - minValus) / perunit_valus * perUnitCellHeifht;
canvas.drawCircle(cx, -cy, 5, paint_dot);
LogUtil.e("yuyahao", "(" + cx + "," + (-cy) + ")" + " yalue: " + yalue + " 最小值:" + minValus + "最大值:" + maxValue + " perunit_valus: " + perunit_valus + " perUnitCellHeifht: " + perUnitCellHeifht);
//canvas.drawCircle(cx, y1, 3, paint_dot);
if (i >= 1) {
path.lineTo(cx, -cy);
canvas.drawPath(path, paint_brokenLine);
if (i == (y_array.size() - 1)) {
path.close();
}
LogUtil.e("yuyahao", "(" + cx + "," + (-cy) + ")");
} else if (i == 0) {
path.reset();
path.moveTo(cx, -cy);
}
}
}

/** * 绘制底部的日期 * * @param canvas */ private void drawBottomDateTypeText(Canvas canvas) { if (xValues == null) { return; } canvas.translate(0, myHeightCell); // canvas.drawRect(0,0,getMeasuredWidth() * 1F,perUnitCell * 2f,paint_date); for (int i = 0; i < xValues.size(); i++) { float centerD = perBottomTextLehght * i + perBottomTextLehght; String text = Utils.date2String(Long.parseLong(xValues.get(i)), "MM月dd日"); float textLength = paint_date.measureText(text) / 2; float startX = centerD - textLength; //float startY = perUnitCell * 2; Rect rectf = new Rect(); paint_date.getTextBounds(text, 0, text.length(), rectf); float startY = perUnitCellHeifht * 2 - rectf.height() / 2; canvas.drawText(text, startX, startY, paint_date); } }
/**
* 去一个集合的最大值
*
* @param y_array
* @return
*/
private float getListOgMax(List<Float> y_array) {
if (y_array == null) {
return 0;
}
return Collections.max(y_array);
}

/**
* 绘制单元格
*
* @param canvas
*/
private void drawUniteCell(Canvas canvas) {

for (int i = 0; i < myHeightCell / perUnitCellHeifht; i++) {
float startX = 0;
float startY = i * perUnitCellHeifht;
float endX = getMeasuredWidth();
float endY = i * perUnitCellHeifht;
canvas.drawLine(startX, startY, endX, endY, framPanint);
}

for (int i = 0; i < getMeasuredWidth() / perUnitCellHeifht; i++) {
float startX = i * perUnitCellHeifht;
float startY = 0;
float endX = i * perUnitCellHeifht;
float endY = myHeightCell;
canvas.drawLine(startX, startY, endX, endY, framPanint);
}
}

/**
* 绘制目标线
*
* @param canvas
*/
private void drawGoalLine(Canvas canvas) {
canvas.save();
if (goal_min > 0) {
float getCurrenY = (goal_min - minValus) / perunit_valus * perUnitCellHeifht;
float startX1 = 0;
float startY1 = (getCurrenY == 0 ? (10) : getCurrenY);
float endX1 = currentWidth - 2;
float endY1 = startY1;
canvas.drawLine(startX1, -startY1, endX1, -endY1, paint_gold1);
String resultGroal = "目标:" + goal_min;
canvas.drawText(resultGroal, startX1 + getDrawMyBottomTextDefaultPadding(resultGroal, paint_date), -startY1 - 10, paint_date);
LogUtil.e("yuyahao", "goal_min: " + goal_min + " " + startX1 + " -" + startY1 + " " + endX1 + " -" + endY1);
}
if (goal_max > 0) {
float getCurrenY = (goal_max - minValus) / perunit_valus * perUnitCellHeifht;
float startX2 = 0;
float startY2 = (getCurrenY == 0 ? (10) : getCurrenY);
;
float endX2 = currentWidth - 2;
float endY2 = startY2;
canvas.drawLine(startX2, -startY2, endX2, -endY2, paint_gold1);
String resultGroal = "目标:" + goal_max;
canvas.drawText(resultGroal, startX2 + getDrawMyBottomTextDefaultPadding(resultGroal, paint_date), -startY2 - 10, paint_date);
LogUtil.e("yuyahao", "goal_max: " + goal_max + " " + startX2 + " -" + startY2 + " " + endX2 + " -" + endY2);
}
if (goal > 0) {
float getCurrenY = (goal - minValus) / perunit_valus * perUnitCellHeifht;
float startX = 0;
float startY = (getCurrenY == 0 ? (10) : getCurrenY);
float endX = currentWidth - 2;
float endY = startY;
canvas.drawLine(startX, -startY, endX, -endY, paint_gold1);
String resultGroal = "目标:" + goal;
canvas.drawText("目标:" + goal, startX + getDrawMyBottomTextDefaultPadding(resultGroal, paint_date), -startY - 10, paint_date);
LogUtil.e("yuyahao", "goal: " + goal + " " + startX + " -" + startY + " " + endX + " -" + endY);
}
}

/**
* 去一个集合的最小值
*
* @param y_array
* @return
*/
private float getListOgMin(List<Float> y_array) {
if (y_array == null) {
return 0;
}
return Collections.min(y_array);
}

/**
* 是否绘制底部的小方格
*
* @param drawRectBackgrodund
*/
public void setDrawRectBackgrodund(boolean drawRectBackgrodund) {
isDrawRectBackgrodund = drawRectBackgrodund;
invalidate();
}

/**
* 设置绘制底部的小方格的颜色
*
* @param resColorId
*/
public void setDrawRectBackgrodundPaintColor(int resColorId) {
framPanint.setColor(ContextCompat.getColor(context, resColorId));
invalidate();
}

/**
* 设置目标值
*
* @param goal_min,goal_max
*/
public void setMyGoadToLine(int goal_min, int goal_max) {
this.goal_min = goal_min;
this.goal_max = goal_max;

maxValue = getListOgMax(y_array);
maxValue = Math.max(maxValue, goal_max);

minValus = getListOgMin(y_array);
minValus = Math.min(minValus, goal_min);

drawFullDistance = maxValue - minValus;//最大值-最小值
perunit_valus = drawFullDistance / UNIT_NUM;
postInvalidate();
}
/**
* 重新设置数据进行刷新
*
* @param
*/
public void setMyChangedData(List<String> xValues, List<Float> y_array) {
this.xValues = xValues;
this.y_array = y_array;
initData();
initDefaltData();
postInvalidate();
}

/**
* 设置目标值1
*
* @param goal
*/
public void setGoal_one(int goal) {
this.goal = goal;
maxValue = getListOgMax(y_array);
minValus = getListOgMin(y_array);
if (goal > maxValue) {
maxValue = goal;
}
if (goal < minValus) {
minValus = goal;
}
drawFullDistance = maxValue - minValus;//最大值-最小值
perunit_valus = drawFullDistance / UNIT_NUM;
postInvalidate();
}

/**
* 适配 绘制目标文字的左边的距离
*
* @param string
* @param paint
* @return
*/
private float getDrawMyBottomTextDefaultPadding(String string, Paint paint) {
float length = paint.measureText(string);
float ff = paint.measureText("目标:" + 20);
if (length == ff) {
return perUnitCellHeifht * 2.2F;
} else {
return perUnitCellHeifht * 2.5F;
}
}

/**
* 设置背景颜色
*
* @param resColor
*/
public void setMyBackgroundColor(int resColor) {
isDrawRectBackgrodundColor = true;
if (resColor != 0) {
paintBg.setColor(ContextCompat.getColor(context, resColor));
}
}

}
Activity中:

private LinearLayout ll_content;
private MyBrokenLineView myBrokenLineView;
private java.util.List<String> xValues;
private List<Float> y_array;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ll_content = (LinearLayout) findViewById(R.id.ll_content);
xValues = new ArrayList<>();
y_array = new ArrayList<>();
for (int i = 0; i < 6; i++) {
xValues.add(System.currentTimeMillis()+"");
}
y_array.add(30F);
y_array.add(70F);
y_array.add(80F);
y_array.add(90F);
y_array.add(60F);
y_array.add(150F);
;
myBrokenLineView = new MyBrokenLineView(MainActivity.this,xValues,y_array);
ll_content.addView(myBrokenLineView);
//myBrokenLineView.setGoal_one(75);
myBrokenLineView.setMyGoadToLine(75,120);//绘制两根目标线
myBrokenLineView.setMyBackgroundColor(R.color.black4);
myBrokenLineView.setDrawRectBackgrodund(true);
//handler.sendEmptyMessageDelayed(100,1000);
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 100:
y_array.clear();
xValues.clear();
for (int i = 0; i < 6; i++) {
y_array.add((float)Math.round(Math.random()*(40)+60));
xValues.add((""+Math.round(Math.random()*(System.currentTimeMillis()- 60 * 60 *24 *30) + System.currentTimeMillis()- 60 * 60 *24 *30)));
}
myBrokenLineView.setGoal_one((int) Math.round(Math.random()*(40)+60));
myBrokenLineView.setMyChangedData(xValues,y_array);

handler.sendEmptyMessageDelayed(100,1000);
break;
}
}
};


项目地址:http://download.csdn.net/detail/androidstarjack/9708431

老于的博客http://blog.csdn.net/androidstarjack



另外你觉得此篇文章对您有所帮助 请关注终端研发部,QQ交流群 :232203809

微信公众号:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: