作者:XINHAO_HAN
更新:2019/06/26
可以说大部分网上下载的,库都比较大,而且作者考虑的都比较全,所以有些东西并不是那么方便,
这块有一个需求就是在图表上画一个最高最低线,我原先用的Mp库,感觉不是很方便,而且项目还是有点庞大
所以自己就写了一个,供大家参考
数据使用
效果图:
![](https://img.haomeiwen.com/i5337239/c7adba2494a81eae.gif)
版效果图:
![](https://img.haomeiwen.com/i5337239/53c1560a707573d0.gif)
思路:
根据需求有个竖状表,每个表格的高度是 [View高度/(最大值 - 最小值)] = 每个等份的高度,然后再乘以传入进来的数值
滑动处理我采用了更改坐标制度
Demo写的不是很好,只供一个参考,0.0
XML
<com.example.xhcharlib.XHLineChar
android:layout_width="match_parent"
android:layout_height="300dp"
android:id="@+id/xhchar"
></com.example.xhcharlib.XHLineChar>
代码使用
xhLineChar.setMaxTable(200.5f);//表的最高状态
xhLineChar.setMinTable(0f);//表的最低状态
ArrayList<XHData> 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)作者重新写了一版,代码较为工整
更新:https://github.com/hanxinhao000/newXinhaoLine
//工作类介绍(部分)
//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<LineCharBean> mList;
/**
* 通知视图刷新
*/
private PointDataViewRefreshListener mPointDataViewRefreshListener;
/**
* 处理过后的数据
*/
private List<LineCharViewData> mViewPointCoordinatesList;
/**
* View高度
*/
private int mHeight;
/**
* 传入左边刻度线的值
*/
private ArrayList<ScaleLineLifeStringBean> mScaleLineLifeStringBeans;
/**
* 获取刻度线底部的值
*/
private ArrayList<ScaleLineBoomStringBean> 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<LineCharBean> 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<Integer> 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<LineCharViewData> getViewPointCoordinatesList() {
return mViewPointCoordinatesList;
}
/**
* 用户通知刷新数据
*/
@Override
public void notifyDataSetChanged() {
}
/**
* 设置刻度线左边的值
*/
@Override
public void setScaleLineLifeStringBeans(ArrayList<ScaleLineLifeStringBean> scaleLineLifeStringBeans) {
mScaleLineLifeStringBeans = scaleLineLifeStringBeans;
}
/**
* 设置刻度线底部的值
*
* @param scaleLineBoomStringBeans
*/
@Override
public void setScaleLineBoomStringBeans(ArrayList<ScaleLineBoomStringBean> scaleLineBoomStringBeans) {
this.scaleLineBoomStringBeans = scaleLineBoomStringBeans;
}
/**
* 获取左边的一些东西
*
* @return
*/
@Override
public ArrayList<ScaleLineLifeStringBean> getScaleLineLifeStringBeans() {
return mScaleLineLifeStringBeans;
}
/**
* 获取底部的一些东西
*
* @return
*/
@Override
public ArrayList<ScaleLineBoomStringBean> getScaleLineBoomStringBeans() {
return scaleLineBoomStringBeans;
}
}
简单版本:github:https://github.com/hanxinhao000/line
载入样式版本:https://github.com/hanxinhao000/lineUp
网友评论