android自定义数据表格,Android简单自定义图表

作者:XINHAO_HAN

更新:2019/06/26

可以说大部分网上下载的,库都比较大,而且作者考虑的都比较全,所以有些东西并不是那么方便,

这块有一个需求就是在图表上画一个最高最低线,我原先用的Mp库,感觉不是很方便,而且项目还是有点庞大

所以自己就写了一个,供大家参考

数据使用

效果图:

69475205205d

1521109504951mzline.gif

版效果图:

样式

69475205205d

1521194439145mzasdf.gif

思路:

根据需求有个竖状表,每个表格的高度是 [View高度/(最大值 - 最小值)] = 每个等份的高度,然后再乘以传入进来的数值

滑动处理我采用了更改坐标制度

Demo写的不是很好,只供一个参考,0.0

XML

android:layout_width="match_parent"

android:layout_height="300dp"

android:id="@+id/xhchar"

>

代码使用

xhLineChar.setMaxTable(200.5f);//表的最高状态

xhLineChar.setMinTable(0f);//表的最低状态

ArrayList xhData = new ArrayList<>();

/*xhData.add(new XHData(20,0));

xhData.add(new XHData(50,80));

xhData.add(new XHData(60,30));

xhData.add(new XHData(80,26));

xhData.add(new XHData(17,26));

xhData.add(new XHData(80,65));

xhData.add(new XHData(26,74));

xhData.add(new XHData(20,86));*/

xhData.add(new XHData(true,5.5f,"2018/3",Color.parseColor("#dd7e6b")));

//标记,表的数据/日期/点的颜色(默认#adadad)

xhData.add(new XHData(true,5.6f,"2018/3",Color.parseColor("#00ffff")));

xhData.add(new XHData(true,80.5f,"2018/3",Color.parseColor("#6aa84f")));

xhData.add(new XHData(true,70.5f,"2018/3",Color.parseColor("#cc0033")));

xhData.add(new XHData(true,200.5f,"2018/3",Color.parseColor("#66ff33")));

xhData.add(new XHData(true,180.5f,"2018/3",Color.parseColor("#6699ff")));

xhData.add(new XHData(true,160.5f,"2018/3",Color.parseColor("#3366ff")));

xhData.add(new XHData(true,140.5f,"2018/3",Color.parseColor("#00ffff")));

xhData.add(new XHData(true,190.5f,"2018/3",Color.parseColor("#006600")));

xhData.add(new XHData(true,10.5f,"2018/3",Color.parseColor("#FF83FA")));

xhData.add(new XHData(true,30.5f,"2018/3",Color.parseColor("#FF3030")));

xhData.add(new XHData(true,12.5f,"2018/3",Color.parseColor("#FF7F50")));

xhData.add(new XHData(true,5.5f,"2018/3",Color.parseColor("#EE30A7")));

xhData.add(new XHData(true,5.6f,"2018/3"));

xhData.add(new XHData(true,80.5f,"2018/3"));

xhData.add(new XHData(true,70.5f,"2018/3"));

xhData.add(new XHData(true,200.5f,"2018/3"));

xhData.add(new XHData(true,180.5f,"2018/3"));

xhData.add(new XHData(true,160.5f,"2018/3"));

xhData.add(new XHData(true,140.5f,"2018/3/15"));

xhData.add(new XHData(true,190.5f,"2018/3/15"));

xhData.add(new XHData(true,10.5f,"2018/3/15"));

xhData.add(new XHData(true,30.5f,"2018/3/15"));

xhData.add(new XHData(true,12.5f,"2018/3/15"));

xhData.add(new XHData(true,5.5f,"2018/3/15"));

xhData.add(new XHData(true,5.6f,"2018/3/15"));

xhData.add(new XHData(true,80.5f,"2018/3/15"));

xhData.add(new XHData(true,70.5f,"2018/3/15"));

xhData.add(new XHData(true,200.5f,"2018/3/15"));

xhData.add(new XHData(true,180.5f,"2018/3/15"));

xhData.add(new XHData(true,160.5f,"2018/3/15"));

xhData.add(new XHData(true,140.5f,"2018/3/15"));

xhData.add(new XHData(true,190.5f,"2018/3/15"));

xhData.add(new XHData(true,10.5f,"2018/3/15"));

xhData.add(new XHData(true,30.5f,"2018/3/15"));

xhData.add(new XHData(true,12.5f,"2018/3/15"));

xhData.add(new XHData(true,5.5f,"2018/3/15"));

xhData.add(new XHData(true,5.6f,"2018/3/15"));

xhData.add(new XHData(true,80.5f,"2018/3/15"));

xhData.add(new XHData(true,70.5f,"2018/3/15"));

xhData.add(new XHData(true,200.5f,"2018/3/15"));

xhData.add(new XHData(true,180.5f,"2018/3/15"));

xhData.add(new XHData(true,160.5f,"2018/3/15"));

xhData.add(new XHData(true,140.5f,"2018/3/15"));

xhData.add(new XHData(true,190.5f,"2018/3/15"));

xhData.add(new XHData(true,10.5f,"2018/3/15"));

xhData.add(new XHData(true,30.5f,"2018/3/15"));

xhData.add(new XHData(true,12.5f,"2018/3/15"));

xhData.add(new XHData(true,5.5f,"2018/3/15"));

xhData.add(new XHData(true,5.6f,"2018/3/15"));

xhData.add(new XHData(true,80.5f,"2018/3/15"));

xhData.add(new XHData(true,70.5f,"2018/3/15"));

xhData.add(new XHData(true,200.5f,"2018/3/15"));

xhData.add(new XHData(true,180.5f,"2018/3/15"));

xhData.add(new XHData(true,160.5f,"2018/3/15"));

xhData.add(new XHData(true,140.5f,"2018/3/15"));

xhData.add(new XHData(true,190.5f,"2018/3/15"));

xhData.add(new XHData(true,10.5f,"2018/3/15"));

xhData.add(new XHData(true,30.5f,"2018/3/15"));

xhData.add(new XHData(true,12.5f,"2018/3/15"));

xhData.add(new XHData(true,5.5f,"2018/3/15"));

xhData.add(new XHData(true,5.6f,"2018/3/15"));

xhData.add(new XHData(true,80.5f,"2018/3/15"));

xhData.add(new XHData(true,30.5f,"2018/3/15"));

xhData.add(new XHData(true,12.5f,"2018/3/15"));

xhData.add(new XHData(true,5.5f,"2018/3/15"));

xhData.add(new XHData(true,5.6f,"2018/3/15"));

xhData.add(new XHData(true,80.5f,"2018/3/15"));

xhData.add(new XHData(true,70.5f,"2018/3/15"));

xhData.add(new XHData(true,200.5f,"2018/3/15"));

xhData.add(new XHData(true,180.5f,"2018/3/15"));

xhData.add(new XHData(true,160.5f,"2018/3/15"));

xhData.add(new XHData(true,140.5f,"2018/3/15"));

xhData.add(new XHData(true,190.5f,"2018/3/15"));

xhData.add(new XHData(true,10.5f,"2018/3/15"));

xhData.add(new XHData(true,30.5f,"2018/3/15"));

xhData.add(new XHData(true,12.5f,"2018/3/15"));

xhData.add(new XHData(true,5.5f,"2018/3/15"));

xhData.add(new XHData(true,5.6f,"2018/3/15"));

xhData.add(new XHData(true,80.5f,"2018/3/15"));

xhData.add(new XHData(true,70.5f,"2018/3/15"));

xhData.add(new XHData(true,200.5f,"2018/3/15"));

xhData.add(new XHData(true,180.5f,"2018/3/15"));

xhData.add(new XHData(true,160.5f,"2018/3/15"));

xhData.add(new XHData(true,140.5f,"2018/3/15"));

xhData.add(new XHData(true,190.5f,"2018/3/15"));

xhData.add(new XHData(true,10.5f,"2018/3/15"));

xhData.add(new XHData(true,30.5f,"2018/3/15"));

xhData.add(new XHData(true,12.5f,"2018/3/15"));

xhData.add(new XHData(true,5.5f,"2018/3/15"));

xhData.add(new XHData(true,5.6f,"2018/3/15"));

xhData.add(new XHData(true,80.5f,"2018/3/15"));

xhLineChar.setLineHOrLineW(30.3f,90.5f);

xhLineChar.setDataArray(xhData);

这个只是简单实现了一下,效果并不是很好,如果有需求的哥们,可以自己改改style

更新(2019/06/26)作者重新写了一版,代码较为工整

//工作类介绍(部分)

//CharViewData 用户传递数据类

//LineData,ScaleLineData 管理刻度线/边缘线

//PointData 老大哥NB了,管理全部关于坐标的实现

//RollingLine 管理滑动

//Up2DownLineData 高低线(目前BUG:设置如果个高于表刻度线会显示不正常)

//XScale Y轴间隔

//CharDrawLineView 我只管画画

//CharLineView 我只管拿取数据,以及给CharDrawLineView 分配画的工作量

更新(2019/06/26)

代码片段

package erjinzhi.xinhao.xinhaolib.linedata;

import android.graphics.Color;

import android.graphics.Paint;

import java.util.ArrayList;

import java.util.List;

import erjinzhi.xinhao.xinhaolib.databean.CharViewData;

import erjinzhi.xinhao.xinhaolib.databean.LineCharBean;

import erjinzhi.xinhao.xinhaolib.databean.LineCharViewData;

import erjinzhi.xinhao.xinhaolib.databean.ScaleLineBoomStringBean;

import erjinzhi.xinhao.xinhaolib.databean.ScaleLineLifeStringBean;

import erjinzhi.xinhao.xinhaolib.databean.listener.DataNotifyDataSetChangedListener;

import erjinzhi.xinhao.xinhaolib.linedata.idata.IBaseData;

import erjinzhi.xinhao.xinhaolib.linedata.idata.IPointData;

import erjinzhi.xinhao.xinhaolib.linedata.idata.ImpPointData;

import erjinzhi.xinhao.xinhaolib.linedata.listener.IScaleLine;

import erjinzhi.xinhao.xinhaolib.linedata.listener.PointDataViewRefreshListener;

import erjinzhi.xinhao.xinhaolib.utils.UIUtils;

/**

* 专门处理坐标的一个类

*/

public class PointData implements IBaseData, IPointData, DataNotifyDataSetChangedListener, ImpPointData, IScaleLine, ILineData {

/**

* 未处理之前的点数据

*/

private List mList;

/**

* 通知视图刷新

*/

private PointDataViewRefreshListener mPointDataViewRefreshListener;

/**

* 处理过后的数据

*/

private List mViewPointCoordinatesList;

/**

* View高度

*/

private int mHeight;

/**

* 传入左边刻度线的值

*/

private ArrayList mScaleLineLifeStringBeans;

/**

* 获取刻度线底部的值

*/

private ArrayList scaleLineBoomStringBeans;

/**

* 刻度线个数

*/

private int mScale = 0;

/**

* 自带画笔

*/

private Paint mPaint;

/**

* 刻度线的长度

*/

private int mScaleWidth;

/**

* 用户所传递过来的设置

*/

private CharViewData mCharViewData;

//平均值

private float average = 0;

private XScale mXScale;

@Override

public void setCharViewData(CharViewData mCharViewData) {

this.mCharViewData = mCharViewData;

}

@Override

public void setList(List mList) {

this.mList = mList;

mPaint = new Paint();

mViewPointCoordinatesList = new ArrayList<>();

//吧 Y轴的信息算出来

mXScale = new XScale(mList.size());

mPaint.setTextSize(20);

}

public float getAverage() {

return average;

}

//设置View高度

@Override

public void setViewHeight(int mHeight) {

this.mHeight = mHeight;

}

@Override

public void setPointDataViewRefreshListener(PointDataViewRefreshListener mPointDataViewRefreshListener) {

this.mPointDataViewRefreshListener = mPointDataViewRefreshListener;

}

//开始处理点数据

@Override

public void calculate() {

//先初始化画笔

initPaint();

//获取当前最大数

int max = maxiMumNumber();

//获取当前最小数

int mid = miniMumNumber();

//计算当前平均值

averageCalculate(max, mid);

//平均点已计算,开始计算每个点所在的高度

pointHeight(mid);

//高度已计算完毕,开始计算宽度

pointWidth();

//计算左边Text的位置

calculateLifeText(max, mid);

//计算底部Text的位置

calculateBoomText();

//通知视图说数据全部已算好

if (mPointDataViewRefreshListener != null) {

mPointDataViewRefreshListener.refreshPointDataView();

}

}

//设置刻度线个数

@Override

public void setScale(int mScale) {

this.mScale = mScale;

}

//设置刻度线长度

@Override

public void setScaleWidth(int mScaleWidth) {

this.mScaleWidth = mScaleWidth;

}

/**

* 计算刻度线(左边)

*

* @param max

* @param mid

*/

private void calculateLifeText(int max, int mid) {

//刻度线分为10个

int temp = (mScaleWidth / NUMBER_OF_SCALE_LINES);

if (mScaleLineLifeStringBeans == null) {

mScaleLineLifeStringBeans = new ArrayList<>();

} else {

//清空刻度线

mScaleLineLifeStringBeans.clear();

}

//平均刻度线

int t = absoluteValue(max - mid) / (NUMBER_OF_SCALE_LINES);

for (int i = 0; i <= NUMBER_OF_SCALE_LINES; i++) {

ScaleLineLifeStringBean scaleLineLifeStringBean = new ScaleLineLifeStringBean();

scaleLineLifeStringBean.setmX(SCALE);

//获取最大点位置

float maxIndex = getMaxIndex();

//获取最小点位置

float minIndex = getMinIndex();

//再除以N份

float temp_s = (maxIndex - minIndex) / (NUMBER_OF_SCALE_LINES);

//获取底部位置

int boom = mHeight;

boom -= (BOTTOM_DISTANCE + POINT_INTERVAL);

scaleLineLifeStringBean.setmY(boom + (temp_s * i));

scaleLineLifeStringBean.setText((mid + (t * i)) + "");

mScaleLineLifeStringBeans.add(scaleLineLifeStringBean);

}

}

//计算刻度线(底部)

@Override

public void calculateBoomText() {

//整理数据

if (scaleLineBoomStringBeans == null) {

scaleLineBoomStringBeans = new ArrayList<>();

}

//将字符串传入,并计算坐标

for (int i = 0; i < mList.size(); i++) {

ScaleLineBoomStringBean scaleLineBoomStringBean = new ScaleLineBoomStringBean();

scaleLineBoomStringBean.setText(mList.get(i).getTextBoom());

int temp = (mHeight - BOTTOM_DISTANCE + BOOM_TEXT_DISTANCE + 20);

int temp_x = mXScale.getXScales().get(i) + LEFT_DISTANCE + POINT_INTERVAL;

scaleLineBoomStringBean.setmX(temp_x);

scaleLineBoomStringBean.setmY(temp);

//计算线的坐标X startX

int startX = temp_x;

//计算线的坐标Y startY

int startY = mHeight - BOTTOM_DISTANCE;

//计算线的坐标X endX

int endX = temp_x;

//计算线的坐标Y endY

int endY = mHeight - BOTTOM_DISTANCE - NUMBER_OF_SCALE_LINES_LINEG;

scaleLineBoomStringBean.setLineStartX(startX);

scaleLineBoomStringBean.setLineStartY(startY);

scaleLineBoomStringBean.setLineEndX(endX);

scaleLineBoomStringBean.setLineEndY(endY);

scaleLineBoomStringBeans.add(scaleLineBoomStringBean);

}

}

/**

* 取得画笔

*/

@Override

public Paint getPaint() {

return mPaint;

}

//初始化画笔

private void initPaint() {

mPaint.setColor(Color.parseColor("#35ADA7"));

mPaint.setStrokeWidth(20);

mPaint.setAntiAlias(true);

mPaint.setTextSize(30);

}

//计算点的宽度

private void pointWidth() {

ArrayList xScales = mXScale.getXScales();

for (int i = 0; i < mViewPointCoordinatesList.size(); i++) {

LineCharViewData lineCharViewData = mViewPointCoordinatesList.get(i);

//与左边线对齐

int temp = xScales.get(i) + LEFT_DISTANCE;

//点之与线的padding

temp += POINT_INTERVAL;

lineCharViewData.setViewDataX(temp);

}

}

//计算每个点所占用的高度

private void pointHeight(int mid) {

//因为我们用了padding所以要减去相对应的坐标

int tempHeight = mHeight;

tempHeight -= (BOTTOM_DISTANCE + TOP_DISTANCE);

//使用for循环开始乘

for (int i = 0; i < mList.size(); i++) {

//计算之前的点

int data = mList.get(i).getData();

//开始计算每个点实质在View中所占用的高度,并存入

LineCharViewData lineCharViewData = new LineCharViewData();

float midTemp = mid * average;

float temp = data * average;

//减去最小值高度,始终使最小值在底部,不然可能会出现"占位"

temp -= midTemp;

//如果为0的话可能就没有了,所以如果是0的话默认在底部

if (average == 0) {

temp = tempHeight + TOP_DISTANCE;

} else {

//减反,如果不理解的哥们,可去除本行(注释)加以验证

temp = tempHeight - temp;

//减去顶部的距离

temp = temp + TOP_DISTANCE;

//减去padding的距离

temp = temp - POINT_INTERVAL;

}

//设置点信息

lineCharViewData.setViewDataY(temp);

lineCharViewData.setData(data);

mViewPointCoordinatesList.add(lineCharViewData);

}

}

//获取最大点位置

private float getMaxIndex() {

int temp = mViewPointCoordinatesList.get(0).getData();

float index = 0;

for (int i = 0; i < mViewPointCoordinatesList.size(); i++) {

if (mViewPointCoordinatesList.get(i).getData() > temp) {

temp = mViewPointCoordinatesList.get(i).getData();

index = mViewPointCoordinatesList.get(i).getViewDataY();

}

}

return index;

}

//获取最小点位置

private float getMinIndex() {

int temp = mViewPointCoordinatesList.get(0).getData();

float index = 0;

for (int i = 0; i < mViewPointCoordinatesList.size(); i++) {

if (mViewPointCoordinatesList.get(i).getData() < temp) {

temp = mViewPointCoordinatesList.get(i).getData();

index = mViewPointCoordinatesList.get(i).getViewDataY();

}

}

return index;

}

/**

* 计算每个点的平均值

*/

private void averageCalculate(int max, int mid) {

UIUtils.loge("大:" + max + " 小:" + mid);

//用最大值减去最小值 获取中间值(必须为正数)

int middle = absoluteValue(max - mid);

//因为我们用了padding所以要减去相对应的坐标

float tempHeight = mHeight;

tempHeight -= (BOTTOM_DISTANCE + TOP_DISTANCE + (POINT_INTERVAL * 2));

//用高度除以中间值 得到每个点的平均值

//如果为0就直接等于0

if (middle == 0) {

average = tempHeight;

} else {

average = tempHeight / middle;

}

UIUtils.loge(average + " ---每个的等分");

}

/**

* 如果为负数就一定要让他变为正数

*/

private int absoluteValue(int temp) {

if (temp < 0) {

temp *= -1;

}

return temp;

}

/**

* 获取当前最大数

*/

private int maxiMumNumber() {

int temp = mList.get(0).getData();

for (int i = 1; i < mList.size(); i++) {

if (mList.get(i).getData() > temp) {

temp = mList.get(i).getData();

}

}

//如果显示高低线,那就看看高低线的值是不是最大的

if (mCharViewData.isShowUp2DownLine()) {

float max = mCharViewData.getUp2Down()[1];

if (temp < max) {

temp = (int) max;

}

}

return temp;

}

/**

* 获取当前最小数

*/

private int miniMumNumber() {

int temp = mList.get(0).getData();

for (int i = 1; i < mList.size(); i++) {

if (mList.get(i).getData() < temp) {

temp = mList.get(i).getData();

}

}

//如果显示高低线,那就看看高低线的值是不是最大的

if (mCharViewData.isShowUp2DownLine()) {

float min = mCharViewData.getUp2Down()[0];

if (temp > min) {

temp = (int) min;

}

}

return temp;

}

/**

* 获取到计算过后的点

*

* @return

*/

@Override

public List getViewPointCoordinatesList() {

return mViewPointCoordinatesList;

}

/**

* 用户通知刷新数据

*/

@Override

public void notifyDataSetChanged() {

}

/**

* 设置刻度线左边的值

*/

@Override

public void setScaleLineLifeStringBeans(ArrayList scaleLineLifeStringBeans) {

mScaleLineLifeStringBeans = scaleLineLifeStringBeans;

}

/**

* 设置刻度线底部的值

*

* @param scaleLineBoomStringBeans

*/

@Override

public void setScaleLineBoomStringBeans(ArrayList scaleLineBoomStringBeans) {

this.scaleLineBoomStringBeans = scaleLineBoomStringBeans;

}

/**

* 获取左边的一些东西

*

* @return

*/

@Override

public ArrayList getScaleLineLifeStringBeans() {

return mScaleLineLifeStringBeans;

}

/**

* 获取底部的一些东西

*

* @return

*/

@Override

public ArrayList getScaleLineBoomStringBeans() {

return scaleLineBoomStringBeans;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值