最终效果

代码实现

package com.example.chartdemo;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.Nullable;import java.util.List;public class ChartView extends View {public ChartView(Context context) {this(context,null);}public ChartView(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}private int widthMode;private int heightMode;private int widthSize;private int heightSize;private List<Integer> xItems;//X轴 轴项private String xUnit;//X轴 刻度单位private List<Integer> yItems;//Y轴 轴项private String yUnit;//Y轴 刻度单位private List<Integer> dataList;//数据private List<Integer> dataList2;//数据2private int xStepDistance;//X轴 步距private int yStepDistance;//Y轴 步距@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);widthMode = MeasureSpec.getMode(widthMeasureSpec);heightMode = MeasureSpec.getMode(heightMeasureSpec);widthSize = MeasureSpec.getSize(widthMeasureSpec);heightSize = MeasureSpec.getSize(heightMeasureSpec);initPaint();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (xItems==null || xItems.size()==0)return;if (yItems==null || yItems.size()==0)return;//画 X轴=====================================================================================canvas.drawLine(0,heightSize,widthSize, heightSize,zhouPaint);xStepDistance=widthSize/xItems.size();//X轴 步距值for (int a=0;a<xItems.size();a++){//画刻度canvas.drawLine(xStepDistance*a,heightSize,xStepDistance*a, heightSize-10,zhouPaint);//画格子Path gePath=new Path();gePath.moveTo(xStepDistance*a, heightSize);gePath.lineTo(xStepDistance*a, 0);gePath.close();canvas.drawPath(gePath, gePaint);//绘制X轴 刻度文字canvas.drawText(a==xItems.size()-1 ? xItems.get(a)+"("+xUnit+")" : xItems.get(a)+"", xStepDistance*a-10, heightSize-20, textPaint);}canvas.drawLine(widthSize,heightSize,widthSize-10,heightSize-10,zhouPaint);//画末尾箭头//画 Y轴=====================================================================================canvas.drawLine(0,0,0, heightSize,zhouPaint);yStepDistance=heightSize/yItems.size();//Y轴 步距值for (int a=0;a<yItems.size();a++){//画刻度if (a!=0)canvas.drawLine(0,heightSize-(yStepDistance*a),10, heightSize-(yStepDistance*a),zhouPaint);//画格子Path gePath=new Path();gePath.moveTo(0, heightSize-(yStepDistance*a));gePath.lineTo(widthSize, heightSize-(yStepDistance*a));gePath.close();canvas.drawPath(gePath, gePaint);//绘制Y轴 刻度文字canvas.drawText(a==yItems.size()-2 ? yItems.get(a)+"("+yUnit+")" : yItems.get(a)+"", 10, heightSize-(yStepDistance*(a+1)), textPaint);}canvas.drawLine(0,0,10,10,zhouPaint);//画末尾箭头//绘制_数据1===================================================================================double yDataPixel=heightSize/100f; //控件高度的像素个数——与——实际数据的对应关系值 (像素点分给100个数据值)for (int k=0;k<dataList.size();k++){if (k!=dataList.size()-1){canvas.drawLine(xStepDistance*k,(int)(heightSize-(dataList.get(k)*yDataPixel)),xStepDistance*(k+1),(int)(heightSize-(dataList.get(k+1)*yDataPixel)),linePaint);}}//绘制_数据2===================================================================================for (int k=0;k<dataList2.size();k++){if (k!=dataList2.size()-1){canvas.drawLine(xStepDistance*k,(int)(heightSize-(dataList2.get(k)*yDataPixel)),xStepDistance*(k+1),(int)(heightSize-(dataList2.get(k+1)*yDataPixel)), linePaint2);}}}private Paint linePaint;private Paint linePaint2;private Paint zhouPaint;private Paint gePaint;private Paint textPaint;private void initPaint(){linePaint=new Paint();linePaint.setStyle(Paint.Style.FILL_AND_STROKE);//不加这个不显示linePaint.setColor(Color.RED);linePaint.setStrokeWidth(4);linePaint.setAntiAlias(true);//抗锯齿功能linePaint.setARGB(100,255,0,0); //设置:A代表透明度  B代表红  G代表绿  B代表蓝 (范围:0————255)linePaint.setStrokeJoin(Paint.Join.ROUND);//线条连接处样式linePaint.setStrokeCap(Paint.Cap.ROUND);//设置线头模式linePaint2=new Paint();linePaint2.setStyle(Paint.Style.FILL_AND_STROKE);//不加这个不显示linePaint2.setColor(Color.BLUE);linePaint2.setStrokeWidth(4);linePaint2.setAntiAlias(true);//抗锯齿功能linePaint2.setARGB(100,0,0,255);linePaint2.setStrokeJoin(Paint.Join.ROUND);linePaint2.setStrokeCap(Paint.Cap.ROUND);gePaint=new Paint();gePaint.setColor(Color.parseColor("#A3AFB8"));gePaint.setStyle(Paint.Style.STROKE);//不加这个不显示gePaint.setStrokeWidth(0);gePaint.setAntiAlias(true);//抗锯齿功能PathEffect effects = new DashPathEffect(new float[]{5, 10}, 0);//设置绘制虚线gePaint.setPathEffect(effects);zhouPaint=new Paint();zhouPaint.setColor(Color.BLACK);zhouPaint.setStrokeWidth(4);zhouPaint.setAntiAlias(true);//抗锯齿功能textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);textPaint.setTextSize(30);}/*** 设置曲线1 数据* @param dataList*/public void setData(List<Integer> dataList){this.dataList=dataList;postInvalidate();}/*** 设置曲线2 数据* @param dataList*/public void setData2(List<Integer> dataList){this.dataList2=dataList;postInvalidate();}/*** 设置X轴参数* @param xList* @param unit 刻度单位*/public void setDataScaleX(List<Integer> xList,String unit){xItems=xList;xUnit=unit;postInvalidate();}/*** 设置Y轴参数* @param yList* @param unit 刻度单位*/public void setDataScaleY(List<Integer> yList,String unit){yItems=yList;yUnit=unit;postInvalidate();}}

使用方法

第一步:在XML中引用View

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.example.chartdemo.ChartViewandroid:id="@+id/chart"android:background="#EFEFEF"android:layout_margin="20px"android:layout_width="match_parent"android:layout_height="600px" /></androidx.constraintlayout.widget.ConstraintLayout>

第二步:设置数据

package com.example.chartdemo;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.widget.ImageView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);List<Integer> dataList=new ArrayList<>();dataList.add(85);dataList.add(90);dataList.add(70);dataList.add(68);dataList.add(50);dataList.add(43);dataList.add(28);dataList.add(21);dataList.add(30);dataList.add(58);dataList.add(70);dataList.add(55);List<Integer> dataList2=new ArrayList<>();dataList2.add(45);dataList2.add(67);dataList2.add(78);dataList2.add(98);dataList2.add(85);dataList2.add(54);dataList2.add(45);dataList2.add(35);dataList2.add(55);dataList2.add(59);dataList2.add(42);dataList2.add(45);List<Integer> xList=new ArrayList<>();xList.add(1);xList.add(2);xList.add(3);xList.add(4);xList.add(5);xList.add(6);xList.add(7);xList.add(8);xList.add(9);xList.add(10);xList.add(11);xList.add(12);List<Integer> yList=new ArrayList<>();yList.add(10);yList.add(20);yList.add(30);yList.add(40);yList.add(50);yList.add(60);yList.add(70);yList.add(80);yList.add(90);yList.add(100);ChartView chart=(ChartView) findViewById(R.id.chart);chart.setDataScaleX(xList,"月");chart.setDataScaleY(yList,"件");chart.setData(dataList);chart.setData2(dataList2);//===========动效数据代码=================doBarChartDataList();}
}

动效代码

private void doBarChartDataList(){for (int a=0;a<dataList.size();a++){new BarHeartbeat().start(50, a, dataList.get(a), new ActionCallback() {@Overridepublic void toDo(Object o) {List<Integer> list= (List<Integer>) o;dataList.set(list.get(0),list.get(1));chart.setData(dataList);}});}for (int a=0;a<dataList2.size();a++){new BarHeartbeat().start(50, a, dataList2.get(a), new ActionCallback() {@Overridepublic void toDo(Object o) {List<Integer> list= (List<Integer>) o;dataList2.set(list.get(0),list.get(1));chart.setData2(dataList2);}});}}

动效辅助类

package com.soface.chartdemo;import android.os.Looper;
import android.os.Message;import java.util.ArrayList;
import java.util.List;/*** 心跳计时器*/
public class BarHeartbeat {//事件标签public final int ACTION_TAG =0xFF;//要回调的接口private ActionCallback thisActionDo;//Handler事件监听器private android.os.Handler mHandler = new android.os.Handler(Looper.getMainLooper()){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case ACTION_TAG:List<Integer> list= (List<Integer>) msg.obj;thisActionDo.toDo(list);break;}}};//启动public void start(int countDownTime,int index,int maxNumber,ActionCallback actionDo){thisActionDo=actionDo;for (int a=0;a<=maxNumber;a++){Message msg = mHandler.obtainMessage();msg.what = ACTION_TAG;List<Integer> list=new ArrayList<>();list.add(index);list.add(a);msg.obj=list;mHandler.sendMessageDelayed(msg,countDownTime*a);}};}
package com.soface.chartdemo;public interface ActionCallback {void toDo(Object o);}

Android自定义View实现折线统计图相关推荐

  1. Android自定义View —— TypedArray

    在上一篇中Android 自定义View Canvas -- Bitmap写到了TypedArray 这个属性 下面也简单的说一下TypedArray的使用 TypedArray 的作用: 用于从该结 ...

  2. Android 自定义View —— Canvas

    上一篇在android 自定义view Paint 里面 说了几种常见的Point 属性 绘制图形的时候下面总有一个canvas ,Canvas 是是画布 上面可以绘制点,线,正方形,圆,等等,需要和 ...

  3. android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...

    转载:http://blog.csdn.net/xiabing082/article/details/48781489 1.  大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...

  4. Android自定义View:ViewGroup(三)

    自定义ViewGroup本质是什么? 自定义ViewGroup本质上就干一件事--layout. layout 我们知道ViewGroup是一个组合View,它与普通的基本View(只要不是ViewG ...

  5. android 自定义图形,Android自定义View之图形图像(模仿360的刷新球自定

    概述: 360安全卫士的那个刷新球(姑且叫它刷新球,因为真的不知道叫什么好,不是dota里的刷新球!!),里面像住了水一样,生动可爱,看似简单,写起来不太简单,本例程只是实现了它的部分功能而已,说实话 ...

  6. android代码实现手机加速功能,Android自定义View实现内存清理加速球效果

    Android自定义View实现内存清理加速球效果 发布时间:2020-09-21 22:21:57 来源:脚本之家 阅读:105 作者:程序员的自我反思 前言 用过猎豹清理大师或者相类似的安全软件, ...

  7. android中仿qq最新版抽屉,Android 自定义View实现抽屉效果

    Android 自定义View实现抽屉效果 说明 这个自定义View,没有处理好多点触摸问题 View跟着手指移动,没有采用传统的scrollBy方法,而是通过不停地重新布局子View的方式,来使得子 ...

  8. Android 自定义 圆环,Android自定义view实现圆环效果实例代码

    先上效果图,如果大家感觉不错,请参考实现代码. 重要的是如何实现自定义的view效果 (1)创建类,继承view,重写onDraw和onMesure方法 public class CirclePerc ...

  9. android自定义抽奖,Android自定义view制作抽奖转盘

    本文实例为大家分享了Android自定义view制作抽奖转盘的具体代码,供大家参考,具体内容如下 效果图 TurntableActivity package com.bawei.myapplicati ...

最新文章

  1. JavaScript正在完善—解释
  2. HTML5 基础知识
  3. dederss.php美国与,dedecms添加rss订阅功能实现代码
  4. 使用showInputDialog显示输入框
  5. 微软从 Engine Yard 手中收购容器平台 Deis
  6. 自定义Android Switch控件
  7. 吉他调音器(1)之十二平均律
  8. 计算机主板维修,计算机主板维修从业技能全程通(70M)*
  9. wireshark如何抓取本机包
  10. 闪存卡提示格式化怎么办?里面的数据怎么恢复
  11. 你是哪一型---左右脑性格测试(转)
  12. node.js 实现简单爬虫批量下载喜马拉雅音频
  13. Python3高级篇
  14. linux下,Telnet连接输入正确的用户名和密码后,却还一直提示输用户名和密码,解决方案。
  15. 【C语言】位段(详解)
  16. python求平均工资_python实现求和,求平均值——函数
  17. cocos2d-x 如何制作一个类马里奥的横版平台动作游戏 1 献给所有对动作游戏有爱的朋友
  18. 直流马达驱动_PWM加减速(STM32F4 CubeMX)
  19. OC 07 设计模式
  20. 【大厂面试】面试官看了赞不绝口的Redis笔记

热门文章

  1. 微信小程序 模块化注意
  2. 博学谷python_博学谷 python
  3. 很多人读书,追求的是干货,寻求的是立刻行之有效的解决方案。        其实这是一种留在舒适区的阅读方法。         在这个充满不确定的年代,答案不会简单的出现在书里
  4. 跨省游拯救疫后旅游业:汝之蜜糖,彼之砒霜
  5. 作为元宇宙里的潮人,怎能不穿上时髦的数字服装呢?
  6. AlloyTeam:致我们终将组件化的 Web (多图)
  7. 从本子文件名中提取本子的名字
  8. shmget函数与shmat
  9. java集成微信发送模板消息
  10. 基于ssm+mysql的javaee微博博客系统,Java实现类似新浪微博网站、朋友圈分享系统