Android 自定义view柱状图

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);

}

欢迎大神指点

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,565评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,021评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,003评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,015评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,020评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,856评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,178评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,824评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,264评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,788评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,913评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,535评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,130评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,102评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,334评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,298评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,622评论 2 343

推荐阅读更多精彩内容