源码 可能不太优雅 但是主要是提供给出大家一点 思路 相信 Android 只有想不到 没有做不到的。
先看一下效果图:
静止
单点触控
多点触控
部分代码:
EnergyItem.java
package com.example.energycurve.ben; /** * 能耗 Bean * @author keven.cheng * */ public class EnergyItem { public String date; //时间值 public float value; //能量 public String time; //使用时间 public EnergyItem() { super(); } public EnergyItem(String date, float value, String time) { super(); this.date = date; this.value = value; this.time = time; } }
/** * 初始化绘制 * * @param canvas * @param paint */ private void initDraw(Canvas canvas, Paint paint) { paint.setColor(Color.WHITE); paint.setAntiAlias(true); paint.setStrokeWidth(3); /* 裁剪出一个需要的矩阵图 */ Path path = new Path(); PointF point = null; path.moveTo(SPACING, mGradientHeight + SPACING_HEIGHT); for (int i = 0; i < points.size(); i++) { point = points.get(i); path.lineTo(point.x, point.y - SPACING_HEIGHT); } path.lineTo(point.x, mGradientHeight + SPACING_HEIGHT); path.lineTo(SPACING, mGradientHeight + SPACING_HEIGHT); path.close(); Bitmap btm = Bitmap.createBitmap((int) mGradientWidth, (int) mGradientHeight, Config.ARGB_8888); Bitmap creatBitmap = creatBitmap(paint, path, btm); /* 绘制底部的横线、文字、以及向上的线条 */ canvas.drawLine(SPACING, mGradientHeight + SPACING_HEIGHT, mGradientWidth, mGradientHeight + SPACING_HEIGHT, paint); for (int i = 0; i < energyItems.size(); i++) { EnergyItem energy = energyItems.get(i); PointF textPoint = points.get(i); paint.setColor(Color.GRAY); paint.setStrokeWidth(1); // 绘制底部 到上面的线 canvas.drawLine(textPoint.x, mGradientHeight + SPACING_HEIGHT, textPoint.x, SPACING_HEIGHT + WEIGHT + 3, paint); paint.setColor(Color.WHITE); // 绘制底部的 文字 canvas.drawText(energy.date, textPoint.x - 15, mGradientHeight + SPACING_HEIGHT + 20, paint); } /* 绘制虚线 */ Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); PathEffect effects = new DashPathEffect(new float[] { 3, 3, 3, 3 }, 3); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(1); mPaint.setPathEffect(effects); float dottedSpacing = (mGradientHeight - WEIGHT) / 4; float smallDotted = dottedSpacing / 10; for (int i = 1; i <= 4; i++) { Path dottedPath = new Path(); mPaint.setColor(Color.GRAY); mPaint.setAlpha(0x50); dottedPath.moveTo(SPACING, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i); dottedPath.lineTo(mGradientWidth, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i); canvas.drawPath(dottedPath, mPaint); } /* 左边刻度尺 */ float digit = ((maxEnergy.value) / 4 + maxEnergy.value) / 4; for (int i = 1; i <= 4; i++) { paint.setStrokeWidth(1); int digitInt = (int) (digit * i + 1.0e-6); canvas.drawText(String.valueOf(digitInt), SPACING - 25, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + 5, paint); canvas.drawLine(SPACING, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i, SPACING + 10, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i, paint); for (int j = 0; j <= 10; j++) { if (j == 5) { canvas.drawLine(SPACING, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + smallDotted * j, SPACING + 10, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + smallDotted * j, paint); } else { canvas.drawLine(SPACING, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + smallDotted * j, SPACING + 5, mGradientHeight + SPACING_HEIGHT - dottedSpacing * i + smallDotted * j, paint); } } } // 绘制裁剪后的矩阵图 canvas.drawBitmap(creatBitmap, 0, SPACING_HEIGHT, paint); /* 绘制曲线 覆盖 剪切后的锯齿 */ for (int i = 0; i < points.size(); i++) { paint.setStrokeWidth(3); PointF startPoint = points.get(i); if (i + 1 == points.size()) { // 绘制最后一个圆点到底部的 竖线 paint.setStrokeWidth(1); canvas.drawLine(startPoint.x, startPoint.y, startPoint.x, mGradientHeight + SPACING_HEIGHT, paint); // 绘制 最后一个圆点 为剪切的图片 canvas.drawBitmap(mLastPoint, startPoint.x - mLastPoint.getWidth() / 2, startPoint.y - mLastPoint.getHeight() / 2, paint); break; } PointF endPoint = points.get(i + 1); // 绘制曲线,并且覆盖剪切后的锯齿 canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, paint); // 为了使线条圆滑 绘一个点 每个坐标系 绘制一个圆点 canvas.drawPoint(startPoint.x, startPoint.y, paint); }
// 绘制左边的竖线,以及温度的刻度 (由于需要与顶边 产生间距SPACING_HEIGHT)———— 目前模拟 待修改
canvas.drawLine(SPACING, SPACING_HEIGHT, SPACING, mGradientHeight
+ SPACING_HEIGHT, paint);
// 绘制右边的 字(时、天、月)通过Type来进行修改———— 目前模拟 待修改
paint.setTextSize(16);
canvas.drawText("天", mGradientWidth + 5, mGradientHeight
+ SPACING_HEIGHT + 5, paint);
canvas.drawText("度", SPACING - 8, 30, paint);
}
单点触摸
/** * 单点触控操作 * * @param canvas * @param paint */ private void SinglePointTouch(Canvas canvas, Paint paint) { // 顶部的度数框 if (moveXOfFirst < points.get(0).x) { moveXOfFirst = points.get(0).x; } if (moveXOfFirst > points.get(points.size() - 1).x) { moveXOfFirst = points.get(points.size() - 1).x; } float moveX = moveXOfFirst; // 绘制度数框 背景后的 横线 canvas.drawBitmap(mTitleLine, SPACING, mGradientHeight + SPACING_HEIGHT - mTrendLine.getHeight() + 5, paint); // 绘制 移动的 点 onPointMove(canvas, paint, moveXOfFirst, isDown); canvas.drawBitmap( mDegree, moveX - mDegree.getWidth() / 2, (mGradientHeight + SPACING_HEIGHT - mTrendLine.getHeight() + 5) / 2, paint); // 绘制 变动的 能耗为多少 float moveY = getMoveY(moveXOfFirst); float energyHeight = (float) (mGradientHeight + SPACING_HEIGHT) - moveY; String energyText = String.valueOf(energyHeight / spacingOfY); // 为了避免误差 如果单点 手指在X轴 在预定的 X点上 那么直接将显示读书设置为 服务器传回的数据 EnergyItem energy = isInPoint(moveXOfFirst); if (energy != null) { energyText = String.valueOf(energy.value); } int indexOf = energyText.indexOf("."); String substring = energyText.substring(0, indexOf + 2); paint.setTextSize(28); paint.setColor(Color.BLACK); canvas.drawText(substring + "度", moveX - mDegree.getWidth() / 3, mGradientHeight + SPACING_HEIGHT - mTrendLine.getHeight() + mDegree.getHeight() / 3, paint); }
多点触摸
/** * 多点触控操作 * * @param canvas * @param paint */ private void multiPointTouch(Canvas canvas, Paint paint) { paint.setColor(Color.rgb(240, 150, 40)); paint.setStrokeWidth(4); // 计算 多点选择 的两个点 分别处在 屏幕的 某个区域内 并且计算出区域中的点 float pointSpacing = 0.0f; // 两点之间的间距 if (moveXOfFirst < points.get(0).x) { moveXOfFirst = points.get(0).x; } if (moveXOfFirst > points.get(points.size() - 1).x) { moveXOfFirst = points.get(points.size() - 1).x; } if (moveXOfSecond < points.get(0).x) { moveXOfSecond = points.get(0).x; } if (moveXOfSecond > points.get(points.size() - 1).x) { moveXOfSecond = points.get(points.size() - 1).x; } int moveXOfOne = getLocation(moveXOfFirst); int moveXOfTwo = getLocation(moveXOfSecond); // 第一个点 小于 第二个点 if (moveXOfOne < moveXOfTwo) { if (!(moveXOfSecond == points.get(points.size() - 1).x)) { moveXOfTwo = moveXOfTwo - 1; } // 重绘 两点间的 的连接线 canvas.drawLine(moveXOfFirst, getMoveY(moveXOfFirst), points.get(moveXOfOne).x, points.get(moveXOfOne).y, paint); for (int j = moveXOfOne; j < moveXOfTwo; j++) { PointF startPoint = points.get(j); if (j + 1 == points.size()) { // 绘制 最后一个圆点 为剪切的图片 canvas.drawBitmap(mLastPoint, startPoint.x - mLastPoint.getWidth() / 2, startPoint.y - mLastPoint.getHeight() / 2, paint); break; } PointF endPoint = points.get(j + 1); // 绘制曲线,并且覆盖剪切后的锯齿 canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, paint); // 为了使线条圆滑 绘一个点 每个坐标系 绘制一个圆点 canvas.drawPoint(startPoint.x, startPoint.y, paint); } canvas.drawLine(points.get(moveXOfTwo).x, points.get(moveXOfTwo).y, moveXOfSecond, getMoveY(moveXOfSecond), paint); } // 第一个点 大于 第二个点 if (moveXOfOne > moveXOfTwo) { if (!(moveXOfFirst == points.get(points.size() - 1).x)) { moveXOfOne = moveXOfOne - 1; } // 重绘 两点间的 的连接线 canvas.drawLine(moveXOfSecond, getMoveY(moveXOfSecond), points.get(moveXOfTwo).x, points.get(moveXOfTwo).y, paint); for (int j = moveXOfTwo; j < moveXOfOne; j++) { PointF startPoint = points.get(j); if (j + 1 == points.size()) { // 绘制 最后一个圆点 为剪切的图片 canvas.drawBitmap(mLastPoint, startPoint.x - mLastPoint.getWidth() / 2, startPoint.y - mLastPoint.getHeight() / 2, paint); break; } PointF endPoint = points.get(j + 1); // 绘制曲线,并且覆盖剪切后的锯齿 canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, paint); // 为了使线条圆滑 绘一个点 每个坐标系 绘制一个圆点 canvas.drawPoint(startPoint.x, startPoint.y, paint); } canvas.drawLine(points.get(moveXOfOne).x, points.get(moveXOfOne).y, moveXOfFirst, getMoveY(moveXOfFirst), paint); } // 第一个点 等于 第二个点 if (getArea(moveXOfFirst) == getArea(moveXOfSecond)) { canvas.drawLine(moveXOfFirst, getMoveY(moveXOfFirst), moveXOfSecond, getMoveY(moveXOfSecond), paint); } float allEnergy = 0.0f; // 区域内的温度总和 // 第一点小于第二点的情况 if (moveXOfFirst < moveXOfSecond) { pointSpacing = Math.abs(moveXOfSecond - moveXOfFirst) / 2 + moveXOfFirst; // 得到两点间的 能量总计 for (int j = moveXOfOne; j <= moveXOfTwo; j++) { allEnergy += energyItems.get(j).value; } } // 第一点大于第二点的情况 if (moveXOfFirst > moveXOfSecond) { pointSpacing = Math.abs(moveXOfFirst - moveXOfSecond) / 2 + moveXOfSecond; for (int j = moveXOfTwo; j <= moveXOfOne; j++) { allEnergy += energyItems.get(j).value; } } // 第两点相等的情况 if (moveXOfFirst == moveXOfSecond) { pointSpacing = Math.abs(moveXOfFirst); } // 绘制 移动的 点 onPointMove(canvas, paint, moveXOfFirst, isDown); if (eventCount >= 2) { onPointMove(canvas, paint, moveXOfSecond, isDown); } // 绘制度数框 背景后的 横线 canvas.drawBitmap(mTitleLine, SPACING, mGradientHeight + SPACING_HEIGHT - mTrendLine.getHeight() + 5, paint); // 顶部的度数框 canvas.drawBitmap(mDegree, pointSpacing - mDegree.getWidth() / 2 + mTrendLine.getWidth() / 2, (mGradientHeight + SPACING_HEIGHT - mTrendLine.getHeight() + 5) / 2, paint); // 绘制 总共消耗的能耗为多少 String energyText = String.valueOf(allEnergy); int indexOf = energyText.indexOf("."); String substring = energyText.substring(0, indexOf + 2); paint.setTextSize(28); paint.setColor(Color.BLACK); canvas.drawText(substring + "度", pointSpacing - mDegree.getWidth() / 4, mGradientHeight + SPACING_HEIGHT - mTrendLine.getHeight() + mDegree.getHeight() / 3, paint); }
源码下载:EnergyCurve.rar