privateArrayListlist=newArrayList<>();
privateContextcontext;
//默认线的颜色
private static finalStringLINECOLOR="#666666";
//负值的颜色
private static finalStringBLUECOLOR="#8800ffff";
//正值的颜色
private static finalStringREDCOLOR="#666666";
//边距
private final intMARGIN=24;
private final intMARGINTOP=48;
private final intMARGINBOTTOM=48;
private final intVERTICALSPEC=10;//柱状图间距
private intmHeight;
private intmWidth;
private intavarageLine;
private floatmColumnWidth;
private doubleavarageValue;//平均值
privateGestureDetectorgestureDetector;
private inttouchSlop;
private intdownX;
private static booleanisLongPress;
private final intSTOREWIDTH=3;
//底部背景日期颜色
private finalStringCOLOR_BOTTOMDATEBG="#88E2EBF9";
//底部日期颜色
private finalStringCOLOR_BOTTOMDATE="#66666666";
//虚线的颜色
private finalStringCOLOR_DASHLINE="#999999";
//边框的颜色
private finalStringCOLOR_BOX="#999999";
private intindex;
private booleanisCanvas;
private intdateIndex;
private booleanisSet;
private intorange;
private booleanisMoveLeft,isMoveRight;
privateArrayListlocations=newArrayList<>();
publicChartView(Context context) {
super(context);
init(context);
}
publicChartView(Context context,AttributeSet attrs) {
super(context,attrs);
init(context);
}
publicChartView(Context context,AttributeSet attrs, intdefStyleAttr) {
super(context,attrs,defStyleAttr);
init(context);
}
@Override
protected voidonSizeChanged(intw, inth, intoldw, intoldh) {
super.onSizeChanged(w,h,oldw,oldh);
mWidth= w -MARGIN*2;
mHeight= h -MARGINTOP-MARGINBOTTOM*2;
//每个柱状图的宽度 整体宽度-左右边距-左右线的宽度-间隔
mColumnWidth= (mWidth-STOREWIDTH*2-VERTICALSPEC*30) /31.0f;
}
private voidinit(Context context) {
this.context= context;
//系统认为最小的滑动距离
isSet=false;
touchSlop= ViewConfiguration.get(context).getScaledTouchSlop();
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
gestureDetector=newGestureDetector(context, newMyGustrueListener());
}
@Override
protected voidonMeasure(intwidthMeasureSpec, intheightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
intwidthSize = MeasureSpec.getSize(widthMeasureSpec);
intheightSize = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthSize,heightSize);
}
@Override
protected voidonDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制边框及虚线
drawBox(canvas);
if(isSet) {
//绘制左侧数值
drawLeftText(canvas);
//绘制柱状图
//平均值不等于0的时候开始绘制
drawColumnBitmap(canvas);
}
}
@Override
public booleanonTouchEvent(MotionEvent event) {
intaction = event.getAction();
switch(action) {
caseMotionEvent.ACTION_DOWN:
downX= (int) event.getX();
break;
caseMotionEvent.ACTION_MOVE:
intmoveX = (int) event.getX();
intmoveY = (int) event.getY();
intdiffX = Math.abs(moveX -downX);
intfinalMoveX = moveX -MARGIN;//减去左侧边距
//滑动只在范围内开始绘制虚线
if(isLongPress&& moveX >MARGIN&& moveX < (mWidth+MARGIN) && moveY >MARGINTOP&& moveY < (MARGINTOP+mHeight)) {
if(diffX >=touchSlop) {
isCanvas=true;
calculateLong(finalMoveX);
}else{
isCanvas=false;
}
}else{
isCanvas=false;
if(list.size() >31) {
if(moveX -downX>0&& !isMoveLeft) {
orange= moveX -downX+orange;
downX= (int) event.getX();
postInvalidate();
}else if(moveX -downX<0&& !isMoveRight) {
Log.e(TAG,"onTouchEvent: = ");
orange= moveX -downX+orange;
downX= (int) event.getX();
postInvalidate();
}
Log.e(TAG,"onTouchEvent: orange = "+orange);
}
}
break;
caseMotionEvent.ACTION_UP:
caseMotionEvent.ACTION_CANCEL:
isLongPress=false;
postInvalidate();
break;
}
returngestureDetector.onTouchEvent(event);
}
/**
*绘制框架
*/
private voiddrawBox(Canvas canvas) {
Paint paint = getLinePaint();
//绘制边框
Path path =newPath();
path.moveTo(MARGIN,MARGINTOP);
path.lineTo(mWidth+MARGIN,MARGINTOP);
path.lineTo(mWidth+MARGIN,mHeight+MARGINTOP);
path.lineTo(MARGIN,mHeight+MARGINTOP);
path.lineTo(MARGIN,MARGINTOP);
path.close();
canvas.drawPath(path,paint);
path.reset();
//平均值
avarageLine=mHeight/6;
//绘制横线
paint.setPathEffect(newDashPathEffect(new float[]{8,8},0));
paint.setColor(Color.parseColor(COLOR_DASHLINE));
for(inti =1;i <=5;i++) {
intstartY =MARGINTOP+avarageLine* i;
canvas.drawLine(MARGIN,startY,mWidth+MARGIN,startY,paint);
}
}
/**
*绘制左侧数值
**/
private voiddrawLeftText(Canvas canvas) {
Paint paint = getTextPaint(COLOR_BOTTOMDATE,30);
intmaxValueIndex = getMaxValueIndex();
if(maxValueIndex == -1) {
return;
}
double[] doubles = calculateAvarage(list.get(maxValueIndex).getValue());
if(doubles ==null|| doubles.length==0) {
return;
}
String[] leftValues =newString[doubles.length];
//转换成字符串
for(inti =0;i < doubles.length;i++) {
doubleaDouble = doubles[i];
if(aDouble >0) {
leftValues[i] = String.valueOf(String.format("%s%s","+",formatValue(aDouble)));
}else if(aDouble ==0) {
leftValues[i] = String.valueOf(String.format("%s","0.00"));
}elseleftValues[i] = String.valueOf(formatValue(aDouble));
}
for(inti =0;i < leftValues.length;i++) {
canvas.drawText(leftValues[i],MARGIN+10,MARGINTOP-10+avarageLine* i,paint);
}
paint.reset();
}
/**
*绘制柱状图
*/
private voiddrawColumnBitmap(Canvas canvas) {
if(list==null||list.size() ==0) {
Toast.makeText(context,"没有数据",Toast.LENGTH_SHORT).show();
return;
}
Paint paint = getLinePaint();
paint.setStyle(Paint.Style.FILL);
intcenterLine =avarageLine*3+MARGINTOP;
ColumnBean columnBean =list.get(0);
String date_value = columnBean.getDate();
dateIndex= Integer.valueOf(date_value.substring(date_value.lastIndexOf("-") +1)) -1;
for(inti =0;i
ColumnBean columnBean2 =list.get(i);
String date2 = columnBean2.getDate();
intindex2 = Integer.valueOf(date2.substring(date2.lastIndexOf("-") +1)) -1;
//每个柱图的高度
doublevalue =list.get(i).getValue();
doublepercent = value /avarageValue;//比例
doubleendY = Math.abs(percent *avarageLine);
//y点的结束点
if(value <0) {
paint.setColor(Color.GREEN);
endY = centerLine + endY;
}else{
paint.setColor(Color.RED);
endY = centerLine - endY;
}
endY = formatValue(endY);
intstartX = ((int) (index2 * (mColumnWidth+VERTICALSPEC) +MARGIN+STOREWIDTH)/*+ orange*/);
intendX = (int) (startX +mColumnWidth);
intleft =MARGIN+STOREWIDTH;
// if (i == 0 && startX >= left) {
// isMoveLeft = true;
// isMoveRight = false;
// }
//
// if (i == list.size() - 1 && endX <= MARGIN + STOREWIDTH + mWidth) {
// isMoveRight = true;
// isMoveLeft = false;
// }
//
// if (startX < left && endX > left) {
// startX = left;
// }
// int right = left + mWidth;
// if (endY > right && startX < right) {
// endX = right;
// }
// Log.e(TAG, "drawColumnBitmap: endx = " + endX + " startX = " + startX + " i = " + i + " ismoveleft = " + isMoveLeft);
// if (startX >= left && endX <= right) {
Rect rect =newRect();
rect.left= startX;
rect.top= value <0? centerLine : (int) endY;
rect.right= endX;
rect.bottom= value <0? (int) endY : centerLine;
canvas.drawRect(rect,paint);
// }
}
//非常按时绘制底部日期
if(!isLongPress) {
paint.setTextSize(30);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor(COLOR_BOTTOMDATE));
String startDate =list.get(0).getDate();
String endDate =list.get(list.size() -1).getDate();
floattextWidth = paint.measureText(startDate);
intstartX = (int) ((dateIndex* (mColumnWidth+VERTICALSPEC) +MARGIN+STOREWIDTH) - textWidth /2);
intendStartX = (int) ((dateIndex+list.size() -1) * (mColumnWidth+VERTICALSPEC) +MARGIN+STOREWIDTH- textWidth /2);
;
if(startX
startX =MARGIN+STOREWIDTH;
}
if(endStartX + textWidth >MARGIN+STOREWIDTH+mWidth) {
endStartX = (int) (MARGIN+mWidth- textWidth);
}
canvas.drawText(startDate,startX,MARGIN+mHeight+55,paint);
canvas.drawText(endDate,endStartX,MARGIN+mHeight+55,paint);
}
//绘制虚线
if(isLongPress) {
paint.setPathEffect(newDashPathEffect(new float[]{8,8},0));
paint.setStrokeWidth(STOREWIDTH);
paint.setColor(Color.GRAY);
intstartX = (int) ((index+dateIndex) * (mColumnWidth+VERTICALSPEC) +MARGIN+STOREWIDTH+mColumnWidth/2);
canvas.drawLine(startX,MARGINTOP,startX,MARGINTOP+mHeight,paint);
paint.reset();
String date =list.get(index).getDate();
drawBottomText(canvas,paint,startX,date);
}
}
/**
*绘制底部日期及背景
*
*@paramtext文本
*@paramstartX线的起始点X轴
*/
private voiddrawBottomText(Canvas canvas,Paint paint, intstartX,String text) {
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(STOREWIDTH);
//绘制底部日期
paint.setTextSize(40);
paint.setColor(Color.parseColor(COLOR_BOTTOMDATEBG));
inttextLength = (int) paint.measureText(text);
intright = startX + textLength /2+VERTICALSPEC;
intleft = startX - textLength /2-VERTICALSPEC;
if(left
left =MARGIN;
right = left + textLength +VERTICALSPEC*2;
}
if(right >MARGIN+mWidth) {
right =MARGIN+mWidth;
left = right - textLength -VERTICALSPEC*2;
}
//绘制日期的背景
Rect rect =newRect(left,MARGINTOP+mHeight+VERTICALSPEC,right,MARGINTOP+mHeight+50+VERTICALSPEC);
canvas.drawRect(rect,paint);
//绘制底部日期
paint.setTextSize(40);
paint.setTypeface(Typeface.DEFAULT);
paint.setTextAlign(Paint.Align.LEFT);
paint.setColor(Color.parseColor(COLOR_BOTTOMDATE));
canvas.drawText(text,left +VERTICALSPEC,MARGINTOP+mHeight+40+VERTICALSPEC,paint);
}
/**
*计算长按事件的位置
*
*@paramfinalMoveX去除左侧边距的位置
*/
private voidcalculateLong(intfinalMoveX) {
index= (int) ((finalMoveX -VERTICALSPEC/2) / (mColumnWidth+VERTICALSPEC));
if(index>dateIndex+list.size() -1) {
index=list.size() -1;
}else if(index
index=0;
}else{
index= Math.abs(index-dateIndex);
}
if(index<0) {
index=0;
}
postInvalidate();
}
/**
*虚线及边框的画笔
*/
privatePaintgetLinePaint() {
Paint paint =newPaint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(STOREWIDTH);
paint.setAntiAlias(true);
paint.setAlpha(0);
paint.setColor(Color.parseColor(COLOR_BOX));
returnpaint;
}
/**
*获取绘制文本的画笔
*
*@paramtextColor文本颜色
*@paramtextSize文本大小
*@return
*/
privatePaintgetTextPaint(String textColor, inttextSize) {
Paint paint =newPaint();
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(STOREWIDTH);
paint.setAntiAlias(true);
paint.setTextSize(textSize);
paint.setAlpha(0);
paint.setTypeface(Typeface.DEFAULT);
paint.setTextAlign(Paint.Align.LEFT);
paint.setColor(Color.parseColor(textColor));
returnpaint;
}
/**
*获取最大值的索引 如果没有数据返回-1
*/
private intgetMaxValueIndex() {
if(list==null||list.size() ==0) {
Toast.makeText(context,"没有数据",Toast.LENGTH_SHORT).show();
return-1;
}
intsize =list.size();
doubleindexValue = Math.abs(list.get(0).getValue());
intindex =0;
for(inti =1;i < size;i++) {
doubletempValue = Math.abs(list.get(i).getValue());
if(tempValue > indexValue) {
indexValue = tempValue;
index = i;
}
}
returnindex;
}
//设置数据
public voidsetData(ArrayList list) {
this.list= list;
isSet=true;
postInvalidate();
}
//计算平均值 并把左侧文案放到数组中
private double[]calculateAvarage(doublemaxValue) {
if(maxValue ==0) {
Toast.makeText(context,"最大值不能是0",Toast.LENGTH_SHORT).show();
return null;
}
avarageValue= maxValue /3;
double[] textValue =new double[7];
inttempIndex =3;
//如果最大值是小数则 大-->小 设置数据
if(maxValue >0) {
for(inti =0;i <7;i++) {
textValue[i] = formatValue(avarageValue* (tempIndex--));
if(tempIndex +1==0) {
textValue[i] =0.00f;
}
}
}else{
for(inti =6;i >=0;i--) {
textValue[i] = formatValue(avarageValue* (tempIndex--));
if(tempIndex +1==0) {
textValue[i] =0.00f;
}
}
}
returntextValue;
}
/**
*全部转换为两位小数
*/
private doubleformatValue(doublevalue) {
DecimalFormat decimalFormat =newDecimalFormat("#.00");
returnDouble.valueOf(decimalFormat.format(value));
}
private intdp2px(intdpValue) {
floatdensity =context.getResources().getDisplayMetrics().density;
return(int) (dpValue * density +0.5f);
}
private intpx2dp(intpxValue) {
floatdensity =context.getResources().getDisplayMetrics().density;
return(int) (pxValue / density +0.5f);
}
private classMyGustrueListenerextendsGestureDetector.SimpleOnGestureListener {
@Override
public booleanonDown(MotionEvent e) {
return true;
}
@Override
public voidonLongPress(MotionEvent e) {
isLongPress=true;
calculateLong((int) (e.getX() -MARGIN));
}
}
数据格式
ArrayList list =newArrayList();
for(inti =0;i <31;i++) {
ColumnBean columnBean =newColumnBean();
doublevalue = (10000- ((Math.random() *20000)));
value = getDecimal(value);
columnBean.setValue(value);
if(i +1<10) {
columnBean.setDate("2016-11-0"+ (i +1));
}else{
columnBean.setDate("2016-11-"+ (i +1));
}
list.add(columnBean);
}