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閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容