最近有需求需要展示蓝牙设备的心率数据,每半小时一个心率值,在图表中显示。有很多第三方的开源图表库可以选择,比如MPAndroidChart等优秀的图表库,最后还是决定自定义vie,上上手,以作练习,效果如下图:
心率数据可以动态设置,刻度值目前在view中设置,各种颜色可在xml文件中配置,接下来记录如何实现。
//点的画笔
private Paint pointPaint;
//连线的画笔
private Paint pathPaint;
//path
private Path linPath;
//点的颜色
private int pointColor;
//点的半径
private float circleRadius;
//线的颜色
private int linColor;
//绘制坐标轴的paint
private Paint xyLinPaint;
//绘制虚线的画笔
private Paint benchPaint;
//绘制y轴刻度的画笔
private Paint yScalePaint;
//是否显示x轴
private boolean isShowX = false;
//是否显示y轴
private boolean isShowY = false;
//宽高
private float mWidth,mHeight;
//数据源
private List<Integer> dataLists = new ArrayList<>();
主要代码,实现起来比较简单
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//坐标平移
canvas.translate(0,mHeight);
canvas.save();
if(!dataLists.isEmpty()){
//间隔的宽度
float mCurrWidth = mWidth / dataLists.size();
//绘制坐标轴
drawXYLin(canvas,mCurrWidth);
//绘制点
for(int i = 0;i<dataLists.size();i++){
//绘制点
canvas.drawCircle(mCurrWidth*i+dp2px(10),-dp2px(dataLists.get(i)),circleRadius,pointPaint);
}
//连线
for(int k = 0;k<dataLists.size();k++){
if(k == 0){
linPath.moveTo(mCurrWidth * k +dp2px(10),-dp2px(dataLists.get(k)));
}else{
linPath.lineTo(mCurrWidth * k +dp2px(10),-dp2px(dataLists.get(k)));
}
}
canvas.drawPath(linPath,pathPaint);
}
}
private void drawXYLin(Canvas canvas,float currWidth) {
//绘制y的标线
if(isShowY){
//60
canvas.drawLine(dp2px(10),-dp2px(60),mWidth,-dp2px(60),benchPaint);
canvas.drawText("60",0,-dp2px(60)+getTextHeight(yScalePaint,60+"")/2,yScalePaint);
//80
canvas.drawLine(dp2px(10),-dp2px(90),mWidth,-dp2px(90),benchPaint);
canvas.drawText("90",0,-dp2px(90)+getTextHeight(yScalePaint,80+"")/2,yScalePaint);
//120
canvas.drawLine(dp2px(10),-dp2px(120),mWidth,-dp2px(120),benchPaint);
canvas.drawText("120",0,-dp2px(120)+getTextHeight(yScalePaint,120+"")/2,yScalePaint);
}
if(isShowX){
//x轴
canvas.drawLine(0,-dp2px(10),mWidth,-dp2px(10),xyLinPaint);
//x轴刻度及下标
for(int i = 0;i<dataLists.size();i++){
canvas.drawLine(currWidth * i +dp2px(10),-dp2px(10),currWidth * i +dp2px(10),-dp2px(15),xyLinPaint);
canvas.drawText(String.valueOf(i+1),currWidth * i +dp2px(10)-getTextWidth(yScalePaint,String.valueOf(i+1))/2,0,yScalePaint);
}
}
}
//设置数据
public void setDataList(List<Integer> dataList) {
this.dataLists = dataList;
linPath.reset();
invalidate();
}
//是否显示x轴的刻度
public void setShowX(boolean showX) {
isShowX = showX;
}
//是否显示y轴的刻度
public void setShowY(boolean showY) {
isShowY = showY;
}
需要注意的地方为,在连线时Paint的Style中有三个枚举,分别为:Style.FILL,Style.STROKE,Style.FILL_AND_STROKE;
Paint.Style.STROKE 只绘制图形轮廓(描边)
Paint.Style.FILL 只绘制图形内容
Paint.Style.FILL_AND_STROKE 既绘制轮廓也绘制内容
这里绘制线,只需要设置STROKE只绘制轮廓即可。目前未加入动画效果,后续再研究加入;GitHub链接: