標籤:highlight 測量 mda val 構造 方式 [] ext
簡介
最近因為項目的需要,需要實現雷達圖來展示各科目的對題率。
雷達圖的繪製不算複雜,只要按照一定的流程來繪製就可以了,其中使用的最多的是path路徑類,使用這個類便於我們繪製出多邊形等效果。
如下:
使用方式
使用方式很簡單,直接在布局檔案裡面使用這個控制項,記得設定一個合適的大小就可以。
當然也有開放一些public方法,可以進行資料、文本顏色等設定。
/** * 設定資料 * @param points */ public void setData(ArrayList<LastPoint> points){} /** * 設定文本 * @param titles */ public void setTitles(String[] titles){} /** * 設定圈數 * @param count */ public void setCount(int count){} /** * 設定網格線顏色 * @param color */ public void setLineColor(int color){} /** * 設定填充地區顏色 * @param color */ public void setValueColor(int color){} /** * 設定文本顏色 * @param color */ public void setTextColor(int color){}
具體實現
一般自訂控制項的流程有以下幾個步驟(個人觀點):
* 1、建構函式(初始化)
* 2、onMeasure(測量大小)
* 3、onSizeChanged(確定大小)
* 4、onLayout(子view的位置,如果包含子view的話)
* 5、onDraw(繪製內容)
* 6、暴露給外部的介面
在該控制項中,2、4都不用考慮,只要確定了大小(onSizeChanged),就能夠計算出整個布局的中心,雷達圖是以這個中心開始繪製的。
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h;
//中心座標 mCenterX = mWidth/2; mCenterY = mHeight/2; mRadius = (Math.min(mWidth,mHeight)/2 * 0.9f); postInvalidate(); }
繪製蜘蛛網圖
/** * 畫網格 * @param canvas */ private void drawLine(Canvas canvas){ Path path = new Path(); //網格線之間的間距 float distance = mRadius / (mCount-1); for (int i = 0; i < mCount; i++){//外面的網格圖形 float currentRadius = i * distance;//當前半徑 if (i == mCount -1){ //儲存最後一圈網格的點的座標 mLastPoints.add(new LastPoint(currentRadius,0)); mLastPoints.add(new LastPoint(currentRadius/2,-currentRadius)); mLastPoints.add(new LastPoint(-currentRadius/2,-currentRadius)); mLastPoints.add(new LastPoint(-currentRadius,0)); mLastPoints.add(new LastPoint(-currentRadius/2,currentRadius)); mLastPoints.add(new LastPoint(currentRadius/2,currentRadius)); } //6個點座標組成一個網格圖形 path.lineTo(currentRadius,0); //設定上一次操作的座標點 path.moveTo(currentRadius,0); path.lineTo(currentRadius/2,-currentRadius); path.lineTo(-currentRadius/2,-currentRadius); path.lineTo(-currentRadius,0); path.lineTo(-currentRadius/2,currentRadius); path.lineTo(currentRadius/2,currentRadius); path.close(); canvas.drawPath(path,mLinePaint); } }
繪製從中心到末端的直線
/** * 畫網格對角線 * @param canvas */ private void drawGridLine(Canvas canvas){ Path path = new Path(); for (int i = 0; i < mLastPoints.size(); i++){ path.reset(); LastPoint point = mLastPoints.get(i); float x = point.x; float y = point.y; path.lineTo(x, y); canvas.drawPath(path, mLinePaint); } }
繪製末端文本
由於文本與末端有一定的距離,所以需要加上一定的位移量;當文本在網格左邊顯示的時候,會與網格有重疊,所以需要先計算文本長度,然後再向左邊位移對應的距離,這樣就可以解決重疊問題。
/** * 畫文本 * @param canvas */ private void drawText(Canvas canvas){ for (int i = 0; i < mLastPoints.size(); i++){ //文本長度 float dis = mTextPaint.measureText(mTitles[i]); LastPoint point = mLastPoints.get(i); float x = point.x; float y = point.y; if (i == 2 || i == 3 || i == 4){ //左邊繪製文本:文本顯示在座標左邊 x = x - dis; } if (y > 0){ y+=18; } canvas.drawText(mTitles[i],x,y,mTextPaint); } }
繪製填充地區
/** * 畫資料線:填充地區 * @param canvas */ private void drawDataLine(Canvas canvas){ if (mDataPoints == null || mDataPoints.size() == 0) return; Path path = new Path(); for (int i = 0; i < mDataPoints.size(); i++){ LastPoint point = mDataPoints.get(i); float x = point.x; float y = point.y; path.lineTo(x, y); if (i == 0){//將上一次操作點移到第一個點座標,保證最後調用close,形成一個封閉的形狀 path.moveTo(x,y); } mValuePaint.setAlpha(255); //畫小圓點 canvas.drawCircle(x,y,8,mValuePaint); } path.close(); mValuePaint.setAlpha(127); canvas.drawPath(path, mValuePaint); }
Android雷達圖(蜘蛛網圖)