Android心率热图实现
16lz
2021-12-04
import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.Path;import android.graphics.Shader;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;import com.careeach.sport.R;import java.util.List;/** * 心率热图 */public class HeartRateView extends View { private List values; private int[] guidesValues; private float height; private float width; private Paint linkLinePoint; private Paint shadePoint; private Paint xTextPoint; private Paint xLintPoint; private Paint yTextPoint; private float itemHeight; //ATTR private int attrXTextColor; private float attrXTextSize; private int attrXLineColor; private float attrXLineWidth; private int attrYTextColor; private float attrYTextSize; private float attrLineWidth; private int attrLinkLineColor; private int attrShadeColor; private float attrGuidesTextMarginLeft; private float attrGuidesTextMarginRight; private float attrPaddingRight; private int maxValue; // 最大值 private float itemWidth; private float contentEndY; private float contentStartX; public HeartRateView(Context context) { super(context); } public HeartRateView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } public HeartRateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } public HeartRateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs); } private void init(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HeartRateView); attrLineWidth = typedArray.getDimension(R.styleable.HeartRateView_hr_lineWidth, dip2px(0.5f)); attrLinkLineColor = typedArray.getColor(R.styleable.HeartRateView_hr_linkLineColor, Color.RED); attrShadeColor = typedArray.getColor(R.styleable.HeartRateView_hr_shadeColor, Color.RED); maxValue = typedArray.getInteger(R.styleable.HeartRateView_hr_maxValue, 180); attrXTextColor = typedArray.getColor(R.styleable.HeartRateView_hr_xTextColor, Color.GRAY); attrXTextSize = typedArray.getDimension(R.styleable.HeartRateView_hr_xTextSize, 20); attrXLineColor = typedArray.getColor(R.styleable.HeartRateView_hr_xLineColor, Color.GRAY); attrYTextSize = typedArray.getDimension(R.styleable.HeartRateView_hr_yTextSize, 20); attrYTextColor = typedArray.getColor(R.styleable.HeartRateView_hr_yTextColor, Color.GRAY); attrXLineWidth = typedArray.getDimension(R.styleable.HeartRateView_hr_xLineWidth, dip2px(0.5f)); attrGuidesTextMarginLeft = typedArray.getDimension(R.styleable.HeartRateView_hr_guidesTextMarginLeft, 20); attrGuidesTextMarginRight = typedArray.getDimension(R.styleable.HeartRateView_hr_guidesTextMarginRight, 20); attrPaddingRight = typedArray.getDimension(R.styleable.HeartRateView_hr_paddingRight, 20); typedArray.recycle(); linkLinePoint = new Paint(); linkLinePoint.setColor(attrLinkLineColor); linkLinePoint.setStrokeWidth(attrLineWidth); linkLinePoint.setStyle(Paint.Style.STROKE); linkLinePoint.setAntiAlias(true); shadePoint = new Paint(); shadePoint.setStyle(Paint.Style.FILL); xTextPoint = new Paint(); xTextPoint.setColor(attrXTextColor); xTextPoint.setTextSize(attrXTextSize); xTextPoint.setAntiAlias(true); yTextPoint = new Paint(); yTextPoint.setColor(attrYTextColor); yTextPoint.setTextSize(attrYTextSize); yTextPoint.setAntiAlias(true); xLintPoint = new Paint(); xLintPoint.setColor(attrXLineColor); xLintPoint.setStrokeWidth(attrXLineWidth); xLintPoint.setAntiAlias(true); xLintPoint.setStyle(Paint.Style.STROKE); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = getMeasuredWidth(); height = getMeasuredHeight(); contentEndY = height - measureTextHeight(xTextPoint); itemHeight = contentEndY / maxValue; contentStartX = attrGuidesTextMarginLeft + yTextPoint.measureText(String.valueOf(maxValue)) + attrGuidesTextMarginRight; } public static float measureTextHeight(Paint paint) { float height = 0f; if (null == paint) { return height; } Paint.FontMetrics fontMetrics = paint.getFontMetrics(); height = fontMetrics.descent - fontMetrics.ascent; return height; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (guidesValues != null && guidesValues.length > 0) { for (int guidesValue : guidesValues) { float x = attrGuidesTextMarginLeft; float y = contentEndY - guidesValue * itemHeight; canvas.drawText(String.valueOf(guidesValue), x, y, yTextPoint); } } if (values != null && values.size() > 1) { Path path = new Path(); Path pathLine = new Path(); path.moveTo(contentStartX, contentEndY - values.get(0) * itemHeight); pathLine.moveTo(contentStartX, contentEndY - values.get(0) * itemHeight); for (int i = 1; i < values.size(); i++) { float x = contentStartX + i * itemWidth; float y = contentEndY - values.get(i) * itemHeight; // 为了美观,计算误差在最后一个点消除 if (i == values.size() - 1) { x = width - attrPaddingRight; } path.lineTo(x, y); pathLine.lineTo(x, y); } path.lineTo(width - attrPaddingRight, contentEndY); path.lineTo(contentStartX, contentEndY); path.lineTo(contentStartX, contentEndY - values.get(0) * itemHeight); path.close(); Shader mShader = new LinearGradient(0, contentEndY, 0, 0, Color.WHITE, attrShadeColor, Shader.TileMode.MIRROR); shadePoint.setShader(mShader); canvas.drawPath(path, shadePoint); canvas.drawPath(pathLine, linkLinePoint); } // X 轴 canvas.drawLine(0, contentEndY, width, contentEndY, xLintPoint); } public void setValues(List values) { this.values = values; itemWidth = (width - attrPaddingRight - contentStartX) / values.size(); postInvalidate(); } /** * 设置参考值 * * @param values */ public void setGuidesValues(int[] values) { this.guidesValues = values; } private float dip2px(float dpValue) { final float scale = getContext().getResources().getDisplayMetrics().density; return (dpValue * scale + 0.5f); }}
attrs.xml添加属性
更多相关文章
- Android之——模拟实现检测心率变化的应用实例
- android 默认系统音量定义
- layout中设置图片自适应大小,并且设置最大宽高
- Android(安卓)ProgressBar的使用
- ProgressBar用法
- Android技能树 — 排序算法基础小结
- 模拟数组pop,push,toString和冒泡排序(sort的使用)
- js 实现数组排序 获取最大值,最小值,翻转
- 做了一个 62 进制的简单实现