Android自定义View实现折线统计图
最终效果
代码实现
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实现折线统计图相关推荐
- Android自定义View —— TypedArray
在上一篇中Android 自定义View Canvas -- Bitmap写到了TypedArray 这个属性 下面也简单的说一下TypedArray的使用 TypedArray 的作用: 用于从该结 ...
- Android 自定义View —— Canvas
上一篇在android 自定义view Paint 里面 说了几种常见的Point 属性 绘制图形的时候下面总有一个canvas ,Canvas 是是画布 上面可以绘制点,线,正方形,圆,等等,需要和 ...
- android自定义view获取控件,android 自定义控件View在Activity中使用findByViewId得到结果为null...
转载:http://blog.csdn.net/xiabing082/article/details/48781489 1. 大家常常自定义view,,然后在xml 中添加该view 组件..如果在 ...
- Android自定义View:ViewGroup(三)
自定义ViewGroup本质是什么? 自定义ViewGroup本质上就干一件事--layout. layout 我们知道ViewGroup是一个组合View,它与普通的基本View(只要不是ViewG ...
- android 自定义图形,Android自定义View之图形图像(模仿360的刷新球自定
概述: 360安全卫士的那个刷新球(姑且叫它刷新球,因为真的不知道叫什么好,不是dota里的刷新球!!),里面像住了水一样,生动可爱,看似简单,写起来不太简单,本例程只是实现了它的部分功能而已,说实话 ...
- android代码实现手机加速功能,Android自定义View实现内存清理加速球效果
Android自定义View实现内存清理加速球效果 发布时间:2020-09-21 22:21:57 来源:脚本之家 阅读:105 作者:程序员的自我反思 前言 用过猎豹清理大师或者相类似的安全软件, ...
- android中仿qq最新版抽屉,Android 自定义View实现抽屉效果
Android 自定义View实现抽屉效果 说明 这个自定义View,没有处理好多点触摸问题 View跟着手指移动,没有采用传统的scrollBy方法,而是通过不停地重新布局子View的方式,来使得子 ...
- Android 自定义 圆环,Android自定义view实现圆环效果实例代码
先上效果图,如果大家感觉不错,请参考实现代码. 重要的是如何实现自定义的view效果 (1)创建类,继承view,重写onDraw和onMesure方法 public class CirclePerc ...
- android自定义抽奖,Android自定义view制作抽奖转盘
本文实例为大家分享了Android自定义view制作抽奖转盘的具体代码,供大家参考,具体内容如下 效果图 TurntableActivity package com.bawei.myapplicati ...
最新文章
- JavaScript正在完善—解释
- HTML5 基础知识
- dederss.php美国与,dedecms添加rss订阅功能实现代码
- 使用showInputDialog显示输入框
- 微软从 Engine Yard 手中收购容器平台 Deis
- 自定义Android Switch控件
- 吉他调音器(1)之十二平均律
- 计算机主板维修,计算机主板维修从业技能全程通(70M)*
- wireshark如何抓取本机包
- 闪存卡提示格式化怎么办?里面的数据怎么恢复
- 你是哪一型---左右脑性格测试(转)
- node.js 实现简单爬虫批量下载喜马拉雅音频
- Python3高级篇
- linux下,Telnet连接输入正确的用户名和密码后,却还一直提示输用户名和密码,解决方案。
- 【C语言】位段(详解)
- python求平均工资_python实现求和,求平均值——函数
- cocos2d-x 如何制作一个类马里奥的横版平台动作游戏 1 献给所有对动作游戏有爱的朋友
- 直流马达驱动_PWM加减速(STM32F4 CubeMX)
- OC 07 设计模式
- 【大厂面试】面试官看了赞不绝口的Redis笔记