最终效果
代码实现
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 BarChartView extends View {
public BarChartView(Context context) {
this(context,null);
}
public BarChartView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public BarChartView(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;//数据2
private int xStepDistance;//X轴 步距
private int yStepDistance;//Y轴 步距
@Override
protected 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();
}
private Paint linePaint;
private Paint linePaint2;
private Paint zhouPaint;
private Paint gePaint;
private Paint zhouTextPaint;
private Paint line1DataTextPaint;
private Paint line2DataTextPaint;
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);//设置线头模式
/*Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable._l9_line_back);
BitmapShader bitmapShader = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.MIRROR);
linePaint.setShader(bitmapShader);*/
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);//抗锯齿功能
zhouTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
zhouTextPaint.setTextSize(30);
line1DataTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
line1DataTextPaint.setARGB(100,255,0,0);
line1DataTextPaint.setTextSize(20);
line2DataTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
line2DataTextPaint.setARGB(100,0,0,255);
line2DataTextPaint.setTextSize(20);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画 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, zhouTextPaint);
}
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)), zhouTextPaint);
}
canvas.drawLine(0,0,10,10,zhouPaint);//画末尾箭头
//绘制_数据1===================================================================================
double yDataPixel=heightSize/100f; //控件高度的像素个数——与——实际数据的对应关系值 (像素点分给100个数据值)
for (int k=0;k<dataList.size();k++){
//画方形条
canvas.drawRect(xStepDistance*k+20,(int)(heightSize-(dataList.get(k)*yDataPixel)),xStepDistance*k+(xStepDistance/2)-30+20,heightSize,linePaint);
canvas.drawText(dataList.get(k)+"", xStepDistance*k+20, (int)(heightSize-(dataList.get(k)*yDataPixel))-20, line1DataTextPaint);
}
//绘制_数据2===================================================================================
for (int k=0;k<dataList2.size();k++){
//画方形条
canvas.drawRect(xStepDistance*k+(xStepDistance/2),(int)(heightSize-(dataList2.get(k)*yDataPixel)),xStepDistance*k+xStepDistance-30,heightSize,linePaint2);
canvas.drawText(dataList2.get(k)+"", xStepDistance*k+(xStepDistance/2), (int)(heightSize-(dataList2.get(k)*yDataPixel))-20, line2DataTextPaint);
}
}
/**
* 设置曲线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中引用
<com.example.chartdemo.BarChartView
android:id="@+id/bar_chart"
android:background="#EFEFEF"
android:layout_margin="20px"
android:layout_width="match_parent"
android:layout_height="600px" />
- 设置参数与数据
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);
BarChartView bar_chart=(BarChartView) findViewById(R.id.bar_chart);
bar_chart.setDataScaleX(xList,"月");
bar_chart.setDataScaleY(yList,"件");
bar_chart.setData(dataList);
bar_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() {
@Override
public void toDo(Object o) {
List<Integer> list= (List<Integer>) o;
dataList.set(list.get(0),list.get(1));
bar_chart.setData(dataList);
}
});
}
for (int a=0;a<dataList2.size();a++){
new BarHeartbeat().start(50, a, dataList2.get(a), new ActionCallback() {
@Override
public void toDo(Object o) {
List<Integer> list= (List<Integer>) o;
dataList2.set(list.get(0),list.get(1));
bar_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()){
@Override
public 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);
}