当前位置:   article > 正文

Android 可左右滑动的动态赛贝尔曲线,纵坐标可设置刻度不均匀_android动态曲线图

android动态曲线图

最近项目中遇到,需要绘制温度实时显示的曲线,纵坐标有三个区间,刻度分别不一致。中间的区域为温度适宜区,显示高度不变,但是刻度会根据实际情况改变。并且要绘制圆滑的曲线,这里使用的是赛贝尔曲线。同时需要在绘制过程中能够左右滑动曲线。下面直接上效果:

赛贝尔曲线使用的是path的方法

path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY, currentPointX, currentPointY);

这里需要使用现有的数据点求出控制点的坐标再绘制

  1. // 求出控制点坐标
  2. final float firstDiffX = (currentPointX - prePreviousPointX);
  3. final float firstDiffY = (currentPointY - prePreviousPointY);
  4. final float secondDiffX = (nextPointX - previousPointX);
  5. final float secondDiffY = (nextPointY - previousPointY);
  6. final float firstControlPointX = previousPointX + (mLineSmoothness * firstDiffX);
  7. final float firstControlPointY = previousPointY + (mLineSmoothness * firstDiffY);
  8. final float secondControlPointX = currentPointX - (mLineSmoothness * secondDiffX);
  9. final float secondControlPointY = currentPointY - (mLineSmoothness * secondDiffY);

自动左右滑动引入了一个第一个点的X坐标变量firstPointX来控制,在添加数据addValue方法的最后判断点是否超过了屏幕宽度,这个时候需要重新计算第一个点的横坐标,重绘时来让曲线看上去在自动往后移动,intervalX变量是每个数据点固定移动的横坐标宽度

  1. firstMinX = CHARTW - originX - (m_plist.size() - 1) * intervalX - leftRightExtra;
  2. if (nx > CHARTW - OFFSET_RIGHT) {
  3. firstPointX = firstPointX - intervalX;
  4. }

手动滑动,重写onTouchEvent方法,postDelayed方法是手抬起后,过几秒会自动回到最后的点,继续自动滑动0

  1. @Override
  2. public boolean onTouchEvent(MotionEvent event) {
  3. if (event.getAction() == MotionEvent.ACTION_UP) {
  4. Log.d("jokey", "onTouchEvent-->ACTION_UP");
  5. myHander.postDelayed(new Runnable() {
  6. @Override
  7. public void run() {
  8. if (m_plist != null && m_plist.size() > 0 && m_plist.get(m_plist.size() - 1).x > CHARTW - OFFSET_RIGHT) {
  9. firstPointX = originX - (intervalX * m_plist.size() - (CHARTW - OFFSET_RIGHT));
  10. }
  11. }
  12. }, 2000);
  13. } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
  14. Log.d("jokey", "onTouchEvent-->ACTION_DOWN");
  15. myHander.removeCallbacksAndMessages(null);
  16. }
  17. if (m_plist != null && m_plist.size() > 0 && m_plist.get(m_plist.size() - 1).x < CHARTW - OFFSET_RIGHT) {
  18. return false;
  19. }
  20. gestureDetector.onTouchEvent(event);
  21. return true;
  22. }

手势事件的控制

  1. /**
  2. * 手势事件
  3. */
  4. class MyOnGestureListener implements GestureDetector.OnGestureListener {
  5. @Override
  6. public boolean onDown(MotionEvent e) { // 按下事件
  7. return false;
  8. }
  9. // 按下停留时间超过瞬时,并且按下时没有松开或拖动,就会执行此方法
  10. @Override
  11. public void onShowPress(MotionEvent motionEvent) {
  12. }
  13. @Override
  14. public boolean onSingleTapUp(MotionEvent motionEvent) { // 单击抬起
  15. return false;
  16. }
  17. @Override
  18. public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
  19. if (e1.getX() > originX && e1.getX() < CHARTW - OFFSET_RIGHT &&
  20. e1.getY() > OFFSET_TOP && e1.getY() < CHARTH - OFFSET_BOTTOM) {
  21. //注意:这里的distanceX是e1.getX()-e2.getX()
  22. distanceX = -distanceX;
  23. if (firstPointX + distanceX > firstMaxX) {
  24. firstPointX = firstMaxX;
  25. } else if (firstPointX + distanceX < firstMinX) {
  26. firstPointX = firstMinX;
  27. } else {
  28. firstPointX = (int) (firstPointX + distanceX);
  29. }
  30. Log.d("jokey", "onScroll-->firstPointX: " + firstPointX);
  31. Log.d("jokey", "onScroll-->firstMaxX: " + firstMaxX);
  32. Log.d("jokey", "onScroll-->firstMinX: " + firstMinX);
  33. invalidate();
  34. }
  35. return false;
  36. }
  37. @Override
  38. public void onLongPress(MotionEvent motionEvent) {
  39. } // 长按事件
  40. @Override
  41. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  42. return false;
  43. }
  44. }

最后来段完整的代码

  1. public class WarmAreDrawChart extends View {
  2. public int CHARTH = 0;
  3. public int CHARTW = 0;
  4. private int originX; // 原点x坐标
  5. private int originY; // 原点y坐标
  6. private int firstPointX;//第一个点x坐标
  7. private int firstMinX; // 移动时第一个点的最小x值
  8. private int firstMaxX; //移动时第一个点的最大x值
  9. private int leftRightExtra = 0;//x轴左右向外延伸的长度
  10. private int OFFSET_LEFT = 0;
  11. private int OFFSET_TOP = 10;
  12. private int OFFSET_RIGHT = 0;
  13. private int OFFSET_BOTTOM = 10;
  14. private int TEXT_OFFSET = 5;
  15. private int intervalX = 25; // x坐标刻度的间隔
  16. private int areWarmMin = 38;//温度适宜区低值
  17. private int areWarmMax = 48;//温度适宜区高值
  18. public int m_nCurrMovePos = 0; //当前点的个数
  19. private int Y_MAX = 50;//Y轴最大值
  20. private int Y_MIN = 35; //Y轴最小值
  21. public List<Point> m_plist, m_plist2, m_plist3;
  22. private Paint paint1, paintBack;
  23. private SimpleDateFormat format = new SimpleDateFormat("mm:ss", Locale.getDefault());
  24. private boolean isFreshTable;
  25. // private int addCount = 0;
  26. private Bitmap bitmap;
  27. public int warmMin, warmMax;
  28. private GestureDetector gestureDetector;
  29. private Handler myHander = new Handler();
  30. // private boolean isGolden;
  31. //曲线切率
  32. private float mLineSmoothness = 0.18f;
  33. private int intervalTimeMs = 100;//数据时间间隔,多少毫秒上传一个数据
  34. public WarmAreDrawChart(Activity activity, int warmMin, int warmMax, int intervalTimeMs) {
  35. super(activity);
  36. this.warmMin = warmMin;
  37. this.warmMax = warmMax;
  38. this.intervalTimeMs = intervalTimeMs;
  39. // this.isGolden = isGolden;
  40. m_plist = new ArrayList<>();
  41. m_plist2 = new ArrayList<>();
  42. m_plist3 = new ArrayList<>();
  43. //画左边的文字
  44. paint1 = new Paint();
  45. paint1.setStyle(Paint.Style.FILL);
  46. paint1.setColor(getResources().getColor(R.color.text_color_666));
  47. paint1.setAntiAlias(true);
  48. paint1.setTextSize(10);
  49. paintBack = new Paint(Paint.ANTI_ALIAS_FLAG);
  50. paintBack.setColor(Color.parseColor("#ffffff"));
  51. paintBack.setStyle(Paint.Style.FILL);
  52. isFreshTable = true;
  53. gestureDetector = new GestureDetector(activity, new MyOnGestureListener());
  54. }
  55. @Override
  56. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  57. if (changed) {
  58. CHARTW = getWidth();
  59. CHARTH = getHeight();
  60. Log.d("jokey", "onLayout-->CHARTW: " + CHARTW);
  61. Log.d("jokey", "onLayout-->CHARTH: " + CHARTH);
  62. originX = OFFSET_LEFT;
  63. originY = CHARTH - OFFSET_BOTTOM;
  64. firstPointX = originX;
  65. Log.d("jokey", "onLayout-->firstPointX: " + firstPointX);
  66. firstMinX = CHARTW - originX - (m_plist.size() - 1) * intervalX - leftRightExtra;
  67. // 滑动时,第一个点x值最大为paddingLeft,在大于这个值就不能滑动了
  68. firstMaxX = firstPointX;
  69. Log.d("jokey", "onLayout-->firstMaxX: " + firstMaxX);
  70. Log.d("jokey", "onLayout-->firstMinX: " + firstMinX);
  71. setBackgroundColor(Color.parseColor("#ffffff"));
  72. }
  73. super.onLayout(changed, left, top, right, bottom);
  74. }
  75. @SuppressLint("DrawAllocation")
  76. @Override
  77. protected void onDraw(Canvas canvas) {
  78. super.onDraw(canvas);
  79. init();
  80. if (bitmap == null) {
  81. return;
  82. }
  83. canvas.drawBitmap(bitmap, 0, 0, null);
  84. drawCurve(canvas);
  85. drawLeftText(canvas);
  86. }
  87. private void init() {
  88. if (isFreshTable) {
  89. if (bitmap != null) {
  90. bitmap.recycle();
  91. bitmap = null;
  92. }
  93. bitmap = Bitmap.createBitmap(CHARTW + OFFSET_LEFT * 2, CHARTH + OFFSET_TOP * 2, Bitmap.Config.ARGB_8888);
  94. Canvas bufferCanvas = new Canvas(bitmap);
  95. drawTable(bufferCanvas);
  96. drawWarmAre(bufferCanvas);
  97. //画模板曲线
  98. isFreshTable = false;
  99. invalidate();
  100. }
  101. }
  102. /**
  103. * 温度适宜区域
  104. *
  105. * @param bufferCanvas
  106. */
  107. private void drawWarmAre(Canvas bufferCanvas) {
  108. //定义画笔
  109. Paint paint = new Paint();
  110. //设置颜色
  111. paint.setColor(0x1A0CACDD);
  112. //设置画笔类型
  113. paint.setStyle(Paint.Style.FILL);
  114. int gapMin = (areWarmMin - Y_MIN);
  115. int gapMax = (areWarmMax - Y_MIN);
  116. //使用画笔在画布上画矩形
  117. bufferCanvas.drawRect(OFFSET_LEFT,
  118. originY - (originY - OFFSET_TOP) * gapMax / 15 + 5,
  119. CHARTW,
  120. originY - (originY - OFFSET_TOP) * gapMin / 15 + 5, paint);
  121. //画温度适宜区文字
  122. Paint paintAreText = new Paint();
  123. paintAreText.setStyle(Paint.Style.FILL);
  124. paintAreText.setColor(getResources().getColor(R.color.color_warm));
  125. paintAreText.setAntiAlias(true);
  126. paintAreText.setTextSize(40);
  127. bufferCanvas.drawText("温 度 适 宜 区 域", (CHARTW - OFFSET_LEFT) / 3, originY - (originY - OFFSET_TOP) * 7 / 15 + 10, paintAreText);
  128. }
  129. private void drawTable(Canvas canvas) {
  130. // paint1.setStyle(Paint.Style.STROKE);
  131. // paint1.setStrokeWidth(2);
  132. // paint1.setColor(getResources().getColor(R.color.red));
  133. // Path path = new Path();
  134. // path.moveTo(originX, OFFSET_TOP);
  135. // path.lineTo(OFFSET_LEFT + CHARTW, OFFSET_TOP);
  136. // for (int i = 1; i < 15; i++) {
  137. // path.moveTo(originX, originY - (originY - OFFSET_TOP) * i / 15);
  138. // path.lineTo(OFFSET_LEFT + CHARTW, originY - (originY - OFFSET_TOP) * i / 15);
  139. // }
  140. // path.moveTo(originX, originY);
  141. // path.lineTo(OFFSET_LEFT + CHARTW, originY);
  142. // canvas.drawPath(path, paint1);
  143. }
  144. private void drawLeftText(Canvas canvas) {
  145. //画左侧数字
  146. canvas.drawText(Y_MAX + "", TEXT_OFFSET, OFFSET_TOP + 5, paint1);
  147. int gapMin = (areWarmMin - Y_MIN);
  148. int gapMax = (areWarmMax - Y_MIN);
  149. canvas.drawText(String.valueOf(warmMin), TEXT_OFFSET, originY - (originY - OFFSET_TOP) * gapMin / 15 + 5, paint1);
  150. canvas.drawText(String.valueOf(warmMax), TEXT_OFFSET, originY - (originY - OFFSET_TOP) * gapMax / 15 + 5, paint1);
  151. canvas.drawText(Y_MIN + "", TEXT_OFFSET, CHARTH - OFFSET_BOTTOM + 7, paint1);
  152. canvas.drawText("℃/min", OFFSET_LEFT + 18, CHARTH, paint1);
  153. }
  154. private void drawCurve(Canvas canvas) {
  155. Paint paintBlue = new Paint(Paint.ANTI_ALIAS_FLAG);
  156. paintBlue.setColor(getResources().getColor(R.color.colorAccent));
  157. paintBlue.setStrokeWidth(2f);
  158. paintBlue.setStyle(Paint.Style.STROKE);
  159. Paint paintGreen = new Paint(Paint.ANTI_ALIAS_FLAG);
  160. paintGreen.setColor(getResources().getColor(R.color.color_19D9CB));
  161. paintGreen.setStrokeWidth(2f);
  162. paintGreen.setStyle(Paint.Style.STROKE);
  163. Paint paintRed = new Paint(Paint.ANTI_ALIAS_FLAG);
  164. paintRed.setColor(getResources().getColor(R.color.color_FE6085));
  165. paintRed.setStrokeWidth(2f);
  166. paintRed.setStyle(Paint.Style.STROKE);
  167. int size = m_plist.size();
  168. //画线
  169. // if (size > 0) {
  170. // for (int i = 0; i < size - 2; i++) {
  171. // canvas.drawLine(firstPointX + i * intervalX, m_plist.get(i).y, firstPointX + (i + 1) * intervalX, m_plist.get(i + 1).y, paintBlue);
  172. // if (m_plist2.size() > 0) {
  173. // canvas.drawLine(firstPointX + i * intervalX, m_plist2.get(i).y, firstPointX + (i + 1) * intervalX, m_plist2.get(i + 1).y, paintGreen);
  174. // }
  175. // if (m_plist3.size() > 0) {
  176. // canvas.drawLine(firstPointX + i * intervalX, m_plist3.get(i).y, firstPointX + (i + 1) * intervalX, m_plist3.get(i + 1).y, paintRed);
  177. // }
  178. // }
  179. // }
  180. Path path = new Path();
  181. // Path path2 = new Path();
  182. // Path path3 = new Path();
  183. float prePreviousPointX = Float.NaN;
  184. float prePreviousPointY = Float.NaN;
  185. float previousPointX = Float.NaN;
  186. float previousPointY = Float.NaN;
  187. float currentPointX = Float.NaN;
  188. float currentPointY = Float.NaN;
  189. float nextPointX;
  190. float nextPointY;
  191. int lineSize = m_plist.size();
  192. for (int i = 0; i < lineSize; i++) {
  193. if (firstPointX + i * intervalX < 0) {
  194. continue;
  195. }
  196. if (firstPointX + i * intervalX > CHARTW) {
  197. break;
  198. }
  199. if (Float.isNaN(currentPointX)) {
  200. currentPointX = firstPointX + i * intervalX;
  201. currentPointY = m_plist.get(i).y;
  202. }
  203. if (Float.isNaN(previousPointX)) {
  204. //是第一个点?
  205. if (i > 0) {
  206. previousPointX = firstPointX + (i - 1) * intervalX;
  207. previousPointY = m_plist.get(i - 1).y;
  208. } else {
  209. //用当前点表示上一个点
  210. previousPointX = currentPointX;
  211. previousPointY = currentPointY;
  212. }
  213. }
  214. if (Float.isNaN(prePreviousPointX)) {
  215. //是前两个点?
  216. if (i > 1) {
  217. prePreviousPointX = firstPointX + (i - 2) * intervalX;
  218. prePreviousPointY = m_plist.get(i - 2).y;
  219. } else {
  220. //当前点表示上上个点
  221. prePreviousPointX = previousPointX;
  222. prePreviousPointY = previousPointY;
  223. }
  224. }
  225. // 判断是不是最后一个点了
  226. if (i < lineSize - 1) {
  227. nextPointX = firstPointX + (i + 1) * intervalX;
  228. nextPointY = m_plist.get(i + 1).y;
  229. } else {
  230. //用当前点表示下一个点
  231. nextPointX = currentPointX;
  232. nextPointY = currentPointY;
  233. }
  234. if (i == 0) {
  235. // 将Path移动到开始点
  236. path.moveTo(currentPointX, currentPointY);
  237. } else {
  238. // 求出控制点坐标
  239. final float firstDiffX = (currentPointX - prePreviousPointX);
  240. final float firstDiffY = (currentPointY - prePreviousPointY);
  241. final float secondDiffX = (nextPointX - previousPointX);
  242. final float secondDiffY = (nextPointY - previousPointY);
  243. final float firstControlPointX = previousPointX + (mLineSmoothness * firstDiffX);
  244. final float firstControlPointY = previousPointY + (mLineSmoothness * firstDiffY);
  245. final float secondControlPointX = currentPointX - (mLineSmoothness * secondDiffX);
  246. final float secondControlPointY = currentPointY - (mLineSmoothness * secondDiffY);
  247. //画出曲线
  248. path.cubicTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,
  249. currentPointX, currentPointY);
  250. }
  251. // 更新
  252. prePreviousPointX = previousPointX;
  253. prePreviousPointY = previousPointY;
  254. previousPointX = currentPointX;
  255. previousPointY = currentPointY;
  256. currentPointX = nextPointX;
  257. currentPointY = nextPointY;
  258. //显示时间
  259. if (i != 0 && i % (60 * (1000 / intervalTimeMs)) == 0) {
  260. canvas.drawText((i / (60 * (1000 / intervalTimeMs))) + "min", firstPointX + i * intervalX, CHARTH - 5, paint1);
  261. }
  262. }
  263. canvas.drawPath(path, paintBlue);
  264. // for (int i = 0; i < size; i++) {
  265. // if (i == 0) {
  266. // path.moveTo(firstPointX, m_plist.get(i).y);
  267. // if (m_plist2 != null && m_plist2.size() > 0) {
  268. // path2.moveTo(firstPointX, m_plist2.get(i).y);
  269. // }
  270. // if (m_plist3 != null && m_plist3.size() > 0) {
  271. // path3.moveTo(firstPointX, m_plist3.get(i).y);
  272. // }
  273. // } else {
  274. // path.lineTo(firstPointX + i * intervalX, m_plist.get(i).y);
  275. // if (m_plist2 != null && m_plist2.size() > 0) {
  276. // path2.lineTo(firstPointX + i * intervalX, m_plist2.get(i).y);
  277. // }
  278. // if (m_plist3 != null && m_plist3.size() > 0) {
  279. // path3.lineTo(firstPointX + i * intervalX, m_plist3.get(i).y);
  280. // }
  281. // }
  282. // }
  283. // canvas.drawPath(path, paintBlue);
  284. // if (m_plist2 != null && m_plist2.size() > 0) {
  285. // paintBlue.setColor(getResources().getColor(R.color.color_19D9CB));
  286. // canvas.drawPath(path2, paintBlue);
  287. // }
  288. // if (m_plist3 != null && m_plist3.size() > 0) {
  289. // paintBlue.setColor(getResources().getColor(R.color.color_FE6085));
  290. // canvas.drawPath(path3, paintBlue);
  291. // }
  292. // 截取折线超出部分(右边)
  293. paintBack.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
  294. RectF rectF = new RectF(CHARTW - OFFSET_RIGHT, 0, CHARTW, CHARTH);
  295. canvas.drawRect(rectF, paintBack);
  296. canvas.save();
  297. canvas.restore();
  298. //将折线超出x轴坐标的部分截取掉(左边)
  299. paintBack.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
  300. rectF = new RectF(0, 0, originX, CHARTH);
  301. canvas.drawRect(rectF, paintBack);
  302. canvas.save();
  303. canvas.restore();
  304. }
  305. public void addValue(ArrayList<List<Integer>> arrayList) {
  306. if (arrayList != null && arrayList.size() > 0) {
  307. if (arrayList.get(0) != null) {
  308. for (int i = 0; i < arrayList.get(0).size(); i++) {
  309. if (arrayList.size() > 1 && arrayList.get(1) != null && arrayList.get(1).size() > 0) {
  310. if (arrayList.size() > 2 && arrayList.get(2) != null && arrayList.get(2).size() > 0) {
  311. addValue(arrayList.get(0).get(i) / 10, arrayList.get(1).get(i) / 10, arrayList.get(2).get(i) / 10);
  312. } else {
  313. addValue(arrayList.get(0).get(i) / 10, arrayList.get(1).get(i) / 10);
  314. }
  315. } else {
  316. addValue(arrayList.get(0).get(i) / 10);
  317. }
  318. }
  319. }
  320. }
  321. }
  322. private int getScreenPosY(double y) {
  323. int gapMin = (areWarmMin - Y_MIN);
  324. int gapMax = (areWarmMax - Y_MIN);
  325. if (y <= warmMin) {
  326. //底部的区域
  327. double ratio = (y - Y_MIN) / (warmMin - Y_MIN);
  328. int height = originY - (originY - OFFSET_TOP) * gapMin / 15 + 5;
  329. int bottom = originY;
  330. return bottom - (int) Math.ceil((bottom - height) * ratio);
  331. } else if (y <= warmMax) {
  332. //中间适宜区
  333. double ratio = (y - warmMin) / (warmMax - warmMin);
  334. int height = originY - (originY - OFFSET_TOP) * gapMax / 15 + 5;
  335. int bottom = originY - (originY - OFFSET_TOP) * gapMin / 15 + 5;
  336. return bottom - (int) Math.ceil((bottom - height) * ratio);
  337. } else {
  338. //顶端区域
  339. double ratio = (y - warmMax) / (Y_MAX - warmMax);
  340. int height = OFFSET_TOP + 5;
  341. int bottom = originY - (originY - OFFSET_TOP) * gapMax / 15 + 5;
  342. return bottom - (int) Math.ceil((bottom - height) * ratio);
  343. }
  344. }
  345. public void addValue(double nValue) {
  346. if (nValue > Y_MAX) {
  347. nValue = Y_MAX;
  348. }
  349. if (nValue > 0 && nValue < Y_MIN) {
  350. nValue = Y_MIN;
  351. }
  352. int ny = getScreenPosY(nValue);
  353. //X坐标一样就不绘制
  354. int nx = OFFSET_LEFT + m_nCurrMovePos * intervalX;
  355. m_nCurrMovePos++;
  356. if (m_plist.size() == 0) {
  357. Point p = new Point(nx, ny);
  358. m_plist.add(p);
  359. } else {
  360. Point p = new Point(nx, ny);
  361. m_plist.add(p);
  362. }
  363. firstMinX = CHARTW - originX - (m_plist.size() - 1) * intervalX - leftRightExtra;
  364. if (nx > CHARTW - OFFSET_RIGHT) {
  365. firstPointX = firstPointX - intervalX;
  366. }
  367. // Log.d("jokey", "addValue-->firstPointX: " + firstPointX);
  368. invalidate();
  369. }
  370. public void addValue(double nValueA, double nValueB) {
  371. if (nValueA >= Y_MAX) {
  372. nValueA = Y_MAX;
  373. }
  374. if (nValueA > 0 && nValueA <= Y_MIN) {
  375. nValueA = Y_MIN;
  376. }
  377. int ny = getScreenPosY(nValueA);
  378. if (nValueB >= Y_MAX) {
  379. nValueB = Y_MAX;
  380. }
  381. if (nValueB > 0 && nValueB <= Y_MIN) {
  382. nValueB = Y_MIN;
  383. }
  384. int ny2 = getScreenPosY(nValueB);
  385. //X坐标一样就不绘制
  386. int nx = OFFSET_LEFT + m_nCurrMovePos * intervalX;
  387. m_nCurrMovePos++;
  388. if (m_plist.size() == 0) {
  389. Point p = new Point(nx, ny);
  390. Point p2 = new Point(nx, ny2);
  391. m_plist.add(p);
  392. m_plist2.add(p2);
  393. } else if ((nx - m_plist.get(m_plist.size() - 1).x) >= 5) {
  394. Point p = new Point(nx, ny);
  395. Point p2 = new Point(nx, ny2);
  396. m_plist.add(p);
  397. m_plist2.add(p2);
  398. }
  399. firstMinX = CHARTW - originX - (m_plist.size() - 1) * intervalX - leftRightExtra;
  400. if (nx > CHARTW - OFFSET_RIGHT) {
  401. firstPointX = firstPointX - intervalX;
  402. }
  403. invalidate();
  404. }
  405. public void addValue(double nValueA, double nValueB, double nValueC) {
  406. Log.d("jokey", "nValueA: " + nValueA + ",nValueB: " + nValueB + ",nValueC: " + nValueC);
  407. if (nValueA >= Y_MAX) {
  408. nValueA = Y_MAX;
  409. }
  410. if (nValueA > 0 && nValueA <= Y_MIN) {
  411. nValueA = Y_MIN;
  412. }
  413. int ny = getScreenPosY(nValueA);
  414. if (nValueB >= Y_MAX) {
  415. nValueB = Y_MAX;
  416. }
  417. if (nValueB > 0 && nValueB <= Y_MIN) {
  418. nValueB = Y_MIN;
  419. }
  420. int ny2 = getScreenPosY(nValueB);
  421. if (nValueC >= Y_MAX) {
  422. Log.d("jokey", "nValueC1: " + nValueC);
  423. nValueC = Y_MAX;
  424. }
  425. if (nValueC > 0 && nValueC <= Y_MIN) {
  426. Log.d("jokey", "nValueC2: " + nValueC);
  427. nValueC = Y_MIN;
  428. }
  429. int ny3 = getScreenPosY(nValueC);
  430. Log.d("jokey", "ny3: " + ny3);
  431. //X坐标一样就不绘制
  432. int nx = OFFSET_LEFT + m_nCurrMovePos * intervalX;
  433. m_nCurrMovePos++;
  434. if (m_plist.size() == 0) {
  435. Point p = new Point(nx, ny);
  436. Point p2 = new Point(nx, ny2);
  437. Point p3 = new Point(nx, ny3);
  438. m_plist.add(p);
  439. m_plist2.add(p2);
  440. m_plist3.add(p3);
  441. } else if ((nx - m_plist.get(m_plist.size() - 1).x) >= 5) {
  442. Point p = new Point(nx, ny);
  443. Point p2 = new Point(nx, ny2);
  444. Point p3 = new Point(nx, ny3);
  445. m_plist.add(p);
  446. m_plist2.add(p2);
  447. m_plist3.add(p3);
  448. }
  449. firstMinX = CHARTW - originX - (m_plist.size() - 1) * intervalX - leftRightExtra;
  450. if (nx > CHARTW - OFFSET_RIGHT) {
  451. firstPointX = firstPointX - intervalX;
  452. }
  453. invalidate();
  454. }
  455. /**
  456. * 手势事件
  457. */
  458. class MyOnGestureListener implements GestureDetector.OnGestureListener {
  459. @Override
  460. public boolean onDown(MotionEvent e) { // 按下事件
  461. return false;
  462. }
  463. // 按下停留时间超过瞬时,并且按下时没有松开或拖动,就会执行此方法
  464. @Override
  465. public void onShowPress(MotionEvent motionEvent) {
  466. }
  467. @Override
  468. public boolean onSingleTapUp(MotionEvent motionEvent) { // 单击抬起
  469. return false;
  470. }
  471. @Override
  472. public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
  473. if (e1.getX() > originX && e1.getX() < CHARTW - OFFSET_RIGHT &&
  474. e1.getY() > OFFSET_TOP && e1.getY() < CHARTH - OFFSET_BOTTOM) {
  475. //注意:这里的distanceX是e1.getX()-e2.getX()
  476. distanceX = -distanceX;
  477. if (firstPointX + distanceX > firstMaxX) {
  478. firstPointX = firstMaxX;
  479. } else if (firstPointX + distanceX < firstMinX) {
  480. firstPointX = firstMinX;
  481. } else {
  482. firstPointX = (int) (firstPointX + distanceX);
  483. }
  484. Log.d("jokey", "onScroll-->firstPointX: " + firstPointX);
  485. Log.d("jokey", "onScroll-->firstMaxX: " + firstMaxX);
  486. Log.d("jokey", "onScroll-->firstMinX: " + firstMinX);
  487. invalidate();
  488. }
  489. return false;
  490. }
  491. @Override
  492. public void onLongPress(MotionEvent motionEvent) {
  493. } // 长按事件
  494. @Override
  495. public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  496. return false;
  497. }
  498. }
  499. @Override
  500. public boolean onTouchEvent(MotionEvent event) {
  501. if (event.getAction() == MotionEvent.ACTION_UP) {
  502. Log.d("jokey", "onTouchEvent-->ACTION_UP");
  503. myHander.postDelayed(new Runnable() {
  504. @Override
  505. public void run() {
  506. if (m_plist != null && m_plist.size() > 0 && m_plist.get(m_plist.size() - 1).x > CHARTW - OFFSET_RIGHT) {
  507. firstPointX = originX - (intervalX * m_plist.size() - (CHARTW - OFFSET_RIGHT));
  508. }
  509. }
  510. }, 2000);
  511. } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
  512. Log.d("jokey", "onTouchEvent-->ACTION_DOWN");
  513. myHander.removeCallbacksAndMessages(null);
  514. }
  515. if (m_plist != null && m_plist.size() > 0 && m_plist.get(m_plist.size() - 1).x < CHARTW - OFFSET_RIGHT) {
  516. return false;
  517. }
  518. gestureDetector.onTouchEvent(event);
  519. return true;
  520. }
  521. }

MainActivity调用

  1. public class MainActivity extends AppCompatActivity {
  2. private MyThread myThread;
  3. private LinearLayout llChart;
  4. private WarmAreDrawChart warmAreDrawChart;
  5. private int intervalTimeMs = 100;
  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. llChart = findViewById(R.id.ll_chart);
  11. initChart();
  12. initListener();
  13. }
  14. private void initListener() {
  15. findViewById(R.id.btn_open).setOnClickListener(new View.OnClickListener() {
  16. @Override
  17. public void onClick(View v) {
  18. open();
  19. });
  20. findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() {
  21. @Override
  22. public void onClick(View v) {
  23. close();
  24. }
  25. });
  26. findViewById(R.id.btn_jie_mian2).setOnClickListener(new View.OnClickListener() {
  27. @Override
  28. public void onClick(View v) {
  29. startActivity(new Intent(MainActivity.this, ListActivity.class));
  30. }
  31. });
  32. }
  33. private void initChart() {
  34. warmAreDrawChart = new WarmAreDrawChart(this, 38, 42, intervalTimeMs);
  35. llChart.removeAllViews();
  36. llChart.addView(warmAreDrawChart);
  37. }
  38. private void open() {
  39. if (myThread == null) {
  40. myThread = new MyThread();
  41. myThread.setContinue(true);
  42. myThread.start();
  43. }
  44. }
  45. private void close() {
  46. if (myThread != null) {
  47. myThread.setContinue(false);
  48. myThread = null;
  49. }
  50. }
  51. private class MyThread extends Thread {
  52. private boolean isContinue;
  53. public void setContinue(boolean aContinue) {
  54. isContinue = aContinue;
  55. }
  56. @Override
  57. public void run() {
  58. while (isContinue) {
  59. int value = new Random().nextInt(16) + 35;
  60. warmAreDrawChart.addValue(value);
  61. SystemClock.sleep(intervalTimeMs);
  62. }
  63. }
  64. }
  65. }

xml布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity">
  8. <LinearLayout
  9. android:id="@+id/ll_chart"
  10. android:layout_width="match_parent"
  11. android:layout_height="200dp"
  12. android:orientation="horizontal">
  13. </LinearLayout>
  14. <LinearLayout
  15. android:layout_width="match_parent"
  16. android:layout_height="wrap_content"
  17. android:layout_alignParentBottom="true"
  18. android:orientation="horizontal">
  19. <Button
  20. android:id="@+id/btn_open"
  21. android:layout_width="wrap_content"
  22. android:layout_height="wrap_content"
  23. android:text="开启"/>
  24. <Button
  25. android:id="@+id/btn_close"
  26. android:layout_width="wrap_content"
  27. android:layout_height="wrap_content"
  28. android:text="关闭"/>
  29. <Button
  30. android:id="@+id/btn_jie_mian2"
  31. android:layout_width="wrap_content"
  32. android:layout_height="wrap_content"
  33. android:text="界面2"/>
  34. </LinearLayout>
  35. </RelativeLayout>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/581000
推荐阅读
相关标签
  

闽ICP备14008679号